Skip to content

Allow content-negotiation for POST requests too #10863

Description

@coyotte508

Describe the problem

I want to do a +server.ts with a POST handler that downloads a file (a JSON backup).

And I want it to be accessible without client-side javascript:

<!-- backup/+page.svelte -->
<form method="POST" action="/backup">
  <input type="submit">
</form>
// backup/+server.ts

export const POST = () => {
  return new Response(JSON.stringify('{}'), {
    headers: {
      'Content-Type': 'application/json',
      'Content-Disposition': 'attachment; filename="backup.json"'
    }
  })
}

Unfortunately, there is a 405 error message with the message:

POST method not allowed. No actions exist for this page

This, despite the lack of +page.server.ts / actions.

Describe the proposed solution

When there is no actions for a page, allow the POST from the native browser form to hit +server.ts's POST handler.

This would be consistent with the GET behavior.

Alternatives considered

Currently, workarounds are using client-side javascript, or redirecting to a GET page in the action's handler.

A possible alternative feature is allow downloading files in an action handler.

Importance

nice to have

Additional Information

No response

Activity

  1. teemingc commented on Oct 12, 2023

    @teemingc
    Member

    The content negotiation seems to be working as intended, but our route handling logic doesn't check if any actions exist first before skipping past our endpoints.

    On a side note, this is what the accept header look like for a native form submission request:

    text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
    
  2. Crisfole commented on Sep 4, 2025

    @Crisfole
    Contributor

    I've got the same exact bug, fully reproed here:

    https://github.com/Crisfole/svelte-kit-bug-demo-repo

  3. added theissue type on Sep 8, 2025
  4. Bishwas-py commented on Jul 14, 2026

    @Bishwas-py
    Contributor

    still reproducible on main, and the underlying gap is also present on version-3.

    version-3 already fixed this exact class of bug for GET/HEAD in #16125, adding a check that falls back to the page when the endpoint can't actually serve the request:
    https://github.com/sveltejs/kit/blob/4674301528/packages/kit/src/runtime/server/respond.js#L638-L647

    that check is scoped to method === 'GET' || method === 'HEAD' only, so POST still goes straight to the endpoint via is_endpoint_request() with no check for whether it has a POST handler, and no fallback to the page's actions. was POST left out on purpose, or just not gotten to yet? if it's the latter, i'll extend the same endpoint_can_handle check to POST and open a PR against main.

  5. added a commit that references this issue on Jul 20, 2026
    5f78e95
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