Skip to content

CSRF failure doesn't pass ActionData to enhanced form callback nor supplies form.error. #10464

Open

Description

@whataboutpereira

Describe the bug

I'm noticing odd behaviour when CSRF fails - when the form is submitted no error message is given.

I see the server is returning code 403 with {message: "Cross-site POST form submissions are forbidden"} which doesn't comply with ActionResult type in the enhance callback function and form.error isn't updated.

{#if form?.success}
	<p class="success">Success</p>
{:else if form?.error}
	<p class="error">{form.error}</p>
{/if}
use:enhance={async ({ formData }) => {
	return async ({ result, update }) => {
		await update();
	};
}}

Is this intended?

How can one catch the 403 error in the callback and/or display a custom message upon CSRF failure?

Right now I can do the following, but cannot force an error message into form.error:

if (result?.type !== 'success' && result?.message) {
	console.log(result.message);
}

Expected format of the CSRF failure would probably be:

{ type: 'error'; status: 403; error: "Cross-site POST form submissions are forbidden"}

Reproduction

https://stackblitz.com/edit/sveltejs-kit-template-default-f1rj2m?file=src%2Froutes%2F%2Bpage.svelte

Logs

No response

System Info

System:
    OS: Linux 5.15 AlmaLinux 8.8 (Sapphire Caracal)
    CPU: (2) x64 Intel(R) Xeon(R) CPU E3-1240 v5 @ 3.50GHz
    Memory: 852.82 MB / 2.00 GB
    Container: Yes
    Shell: 4.4.20 - /bin/bash
  Binaries:
    Node: 16.14.0 - /usr/bin/node
    npm: 8.3.1 - /usr/bin/npm
  npmPackages:
    @sveltejs/adapter-node: ^1.3.1 => 1.3.1 
    @sveltejs/kit: ^1.22.3 => 1.22.3 
    svelte: ^4.1.1 => 4.1.1 
    vite: ^4.4.7 => 4.4.7

Severity

serious, but I can work around it

Additional Information

No response

Activity

  1. teemingc commented on Aug 1, 2023

    @teemingc
    Member

    I agree. We should update the object shape returned from the CSRF failure to align the ActionResult type.

    As an aside, the $page.form store is only updated when returning an object from the action (or with the fail() helper). It does not update when the CSRF failure occurs (because of the weird object shape).
    https://kit.svelte.dev/docs/form-actions#anatomy-of-an-action

    A hacky workaround for now since the result object shape is { message: string } :

    <form
    	method="POST"
    	use:enhance={async ({ formData }) => {
    		return async ({ result, update }) => {
    			if (result?.message === "Cross-site POST form submissions are forbidden") {
    				result.data = {
    					error: "The submission failed"
    				};
    			}
    			await applyAction(result);
    		};
    	}}
    >

    https://stackblitz.com/edit/sveltejs-kit-template-default-rarbe5?file=src%2Froutes%2F%2Bpage.svelte

  2. Blackwidow-sudo commented on Jan 4, 2026

    @Blackwidow-sudo

    It would be best if the ActionResult also exposes the response object.

    I have a very similar issue:
    Infront of my sveltekit app sits a traefik proxy with a rateLimit middleware protecting form actions (POST endpoints).
    When an IP hits the limit, the proxy returns a 429 Too Many Requests. Since this response doesn't conform to the shape of ActionResult, you cant get the status code of the response. So you're not really able to render a warning that the user cannot login for a couple of minutes (for example)

  3. added theissue type on Aug 23, 2026
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

    error handlingformsStuff relating to forms and form actions

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions