Skip to content

Remote form with .for() duplicate requests exponentially #14546

Closed

Description

@bhuynhdev

Describe the bug

When I have multiple forms on the same page that submits to the same Remote function, Svelte recommends me to use a form.for(key) to distinguish between difference form instances (Don't seem to see docs for this anywhere, but the message is in console.log).

Uncaught error: A form object can only be attached to a single `<form>` element.
To create multiple instances, use `updateScore.for(key)

However, using .for() duplicates my request exponentially. First submit sends 1 requests, 2nd submit sends 2 requests, 3rd submits send 4 requests, 4th submit sends 8 requests, and so on...

What strange is that if I remove the .for() part, the Remote form looks to work like normal again.

Reproduction

Here is a Github reproduction repo: https://github.com/bhuynhdev/sveltekit-issue-14546
Here is a SvelteLab link with same content: https://www.sveltelab.dev/gpq6890y483k245?files=.%2Fsrc%2Froutes%2F%2Bpage.svelte

The reproduction step is simple:

  1. Create new project with npx sv create my-app
  2. Install valibot: npm install valibot
  3. Change svelte.config.js to include experimental features
import adapter from '@sveltejs/adapter-auto';
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';

const config = {
	preprocess: vitePreprocess(),
	compilerOptions: {
		experimental: {
			async: true
		},
	},
	kit: {
		adapter: adapter(),
		experimental: {
      remoteFunctions: true
    },
	},
};

export default config;
  1. Create routes/data.remote.js with following content:
import * as v from 'valibot'
import { form, query } from '$app/server'
let SCORE = {
  "amy": 1,
	// "bob": 2,
};

export const listScore = query(async () => {
  const dataAsPromise = await new Promise(resolve => resolve(Object.entries(SCORE)))
  return dataAsPromise
})

export const updateScore = form(
	v.object({name: v.picklist(Object.keys(SCORE))}),
  async (form) => {
    SCORE[form.name] = Number(SCORE[form.name]) + 1
    await listScore().refresh()
  }
)
  1. Update page.svelte to following content:
<script>
  import { listScore, updateScore } from "./data.remote";
  const score = listScore();
</script>

<div>
  <pre>{JSON.stringify(score.current, null, 2)}</pre>
  {#each score.current || [] as [name, _], i (name)}
    <!-- enhance to prevent form reset and potentially do other thing like show toast -->
    <form
      {...updateScore.for(name).enhance(async ({ submit }) => await submit())}
    >
      <input type="hidden" name="name" value={name} />
      <button type="submit">Submit {i}</button>
    </form>
  {/each}
</div>
  1. Run the page with npm run dev
  2. Try clicking the Submit button multiple time on http://localhost:5173

Logs

System Info

System:
    OS: Linux 6.6 Ubuntu 24.04.2 LTS 24.04.2 LTS (Noble Numbat)
    CPU: (32) x64 13th Gen Intel(R) Core(TM) i9-13900HX
    Memory: 13.50 GB / 15.46 GB
    Container: Yes
    Shell: 5.2.21 - /bin/bash
  Binaries:
    Node: 22.17.0 - ~/.local/share/mise/installs/node/22.17.0/bin/node
    npm: 10.9.2 - ~/.local/share/mise/installs/node/22.17.0/bin/npm
    pnpm: 10.15.1 - ~/.local/share/pnpm/pnpm
  npmPackages:
    @sveltejs/adapter-auto: ^6.0.0 => 6.1.0
    @sveltejs/kit: ^2.22.0 => 2.43.5
    @sveltejs/vite-plugin-svelte: ^6.0.0 => 6.2.1
    svelte: ^5.0.0 => 5.39.6
    vite: ^7.0.4 => 7.1.7

Severity

blocking an upgrade

Additional Information

No response

Activity

  1. changed the title [-]Remote `form` with `.for()` duplicate requests expotentially[/-] [+]Remote `form` with `.for()` duplicate requests exponentially[/+] on Sep 27, 2025
  2. sillvva commented on Sep 27, 2025

    @sillvva
    Contributor

    I think the problem is a combination of:

    • {#each} rerunning whenever score.current refreshes creating multiple forms in cache with the same .for() name
    • .enhance() programmatically submitting all cached forms with the designated .for() name

    By removing the .enhance() it behaves as expected.

    https://www.sveltelab.dev/44u25vu267qp2d7

    Alternatively you should prevent the loop from rerunning by importing the names in a separate query, or if hard coded, as a separate import.

    https://www.sveltelab.dev/y795sdtwg5wiki0


    Also, this appears to have been previously reported: #14498


    Ultimately when the each loop, or some other effect, reruns it should clean up the existing form(s) from cache to prevent extra submissions.

  3. added theissue type on Nov 26, 2025
  4. dangodai commented on Nov 27, 2025

    @dangodai

    Just copying my reproduction from the duplicate issue above into this one in case it helps. The circumstances required to trigger the issue seemed very particular in my case.

    Just wish I had found this issue before spending hours narrowing down the problem 😅


    Reproduction: https://www.sveltelab.dev/j093ob9ce3xk50c?files=.%2Fsrc%2Froutes%2F%2Bpage.svelte%2C.%2Fsrc%2Froutes%2Fapi.remote.ts

    Click the button and observe that the calls made double each time. Both the client enhance function and the server form function log when they are called.

    The circumstances I've narrowed it down to so far are

    • Multiple instances of a form using .for() inside of an async each block calling a remote query
    • A top level await followed by a derived promise, which is then awaited in the template
    • The forms use .enhance()
  5. bcharbonnier commented on Nov 28, 2025

    @bcharbonnier

    I can reproduce locally in my application with only an enhance() on the form. No need to use the for().

    I don't think it's related to kit, but more to svelte itself.

    I've never noticed it with version 5.41.x
    Testing with 5.45.2 yesterday, and noticed it right away. Removing the enhance makes it back to normal instantly.

  6. kevlarr commented on Dec 15, 2025

    @kevlarr

    @bcharbonnier Did that ever resolve for you or did you just move away from using enhance?

    Ran into this today with just enhance on a single form, meaning no .for, but it was not happening consistently. Closed the tab and reopened app in another, everything was fine for 10-15 minutes and then it starts popping up again. I feel like I've been seeing a lot of weird little ghosts like that since switching over to async svelte & remote queries/forms.

    Update: Also noticed that, when this issue was happening, prelight-only validation also wasn't working - it was back to making a request to the server for validation that otherwise worked client-side.

  7. added a commit that references this issue on Jan 14, 2026
    a765de1
  8. added a commit that references this issue on Feb 8, 2026
    a315c31
  9. added a commit that references this issue on Feb 19, 2026
    6df9d33
  10. added a commit that references this issue on Mar 6, 2026
    cbd44c1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions