Remix V2: Missing form submission function handler

Hi,

I migrated a larger project from Remix V1 to V2. I did a step by step refactoring.
When testing the app I received the following error message when I tried to send a remix form. It didn’t matter whether I used POST or GET.

» Warning: Missing form submission function handler
Request from ::1: POST /?index=&_data=routes%2F_index
Response with status 404 in 2 ms.
» Warning: Missing form submission function handler
Request from ::1: POST /index.html?index=&_data=routes%2F_index
Response with status 404 in 1 ms.
» Warning: Missing form submission function handler
Request from ::1: POST /index.htm?index=&_data=routes%2F_index
Response with status 404 in 0 ms.

After a long time troubleshooting my source code, I created a simple Hello World page and tested it. It turns out that it must be the Netlify CLI because the test app worked with a Remix template, but produced the error shown with the Netlify template. I carried out many different tests until I came up with the idea of ​​testing the test page in the classic remix setup. I then notice that it runs clean there.

Here are my configurations and the index route.

netlify.toml

[build]
command = "npm run build"
publish = "public"

[dev]
command = "npm run dev"
targetPort = 3000

# Set immutable caching for static files, because they have fingerprinted filenames

[[headers]]
for = "/build/*"

[headers.values]

"Cache-Control" = "public, max-age=31560000, immutable"

remix.config.js

import { config } from "@netlify/remix-adapter";

/** @type {import('@remix-run/dev').AppConfig} */
export default {
  ...(process.env.NODE_ENV === "production" ? config : undefined),
  // This works out of the box with the Netlify adapter, but you can
  // add your own custom config here if you want to.
  //
  // See https://remix.run/file-conventions/remix-config
};

package.json

{
  "name": "",
  "private": true,
  "sideEffects": false,
  "type": "module",
  "scripts": {
    "build": "remix build",
    "dev": "remix dev",
    "start": "netlify serve",
    "typecheck": "tsc -b"
  },
  "dependencies": {
    "@netlify/functions": "^2.0.0",
    "@netlify/remix-adapter": "^2.0.0",
    "@remix-run/node": "^2.4.1",
    "@remix-run/react": "^2.4.1",
    "cross-env": "^7.0.3",
    "react": "^18.2.0",
    "react-dom": "^18.2.0"
  },
  "devDependencies": {
    "@remix-run/dev": "^2.4.1",
    "@remix-run/eslint-config": "^2.4.1",
    "@remix-run/serve": "^2.4.1",
    "@types/react": "^18.2.0",
    "@types/react-dom": "^18.2.0",
    "autoprefixer": "^10.4.16",
    "eslint": "^8.27.0",
    "tailwindcss": "^3.4.1",
    "typescript": "^5.2.2"
  },
  "engines": {
    "node": ">=18"
  }
}

_index.tsx

import { json } from "@remix-run/node";
import {
  Form,
  useActionData,
} from "@remix-run/react";
import type { ActionFunctionArgs } from "@remix-run/node";

export function headers({
  loaderHeaders,
  parentHeaders,
}: {
  loaderHeaders: Headers;
  parentHeaders: Headers;
}) {
  console.log(
    "This is an example of how to set caching headers for a route, feel free to change the value of 60 seconds or remove the header"
  );
  return {
    // This is an example of how to set caching headers for a route
    // For more info on headers in Remix, see: https://remix.run/docs/en/v1/route/headers
    "Cache-Control": "public, max-age=60, s-maxage=60",
  };
}

export const action = async ({
  params,
  request,
}: ActionFunctionArgs) => {
  const formData = await request.formData();
  return json("works");
};

export default function Index() {
  const actionResult = useActionData<typeof action>();
console.log(actionResult);

  return (
    <main style={{ fontFamily: "system-ui, sans-serif", lineHeight: "1.4" }}>
      <h1 className="text-3xl font-bold">
        Hello world!
      </h1>
      <ul>
        <li>
          <a
            target="_blank"
            href="https://remix.run/tutorials/blog"
            rel="noreferrer noopener"
          >
            15m Quickstart Blog Tutorial
          </a>
        </li>
        <li>
          <a
            target="_blank"
            href="https://remix.run/tutorials/jokes"
            rel="noreferrer noopener"
          >
            Deep Dive Jokes App Tutorial
          </a>
        </li>
        <li>
          <a
            target="_blank"
            href="https://remix.run/docs"
            rel="noreferrer noopener"
          >
            Remix Docs
          </a>
        </li>
      </ul>
      <div>
        <Form method="post">
          <button name="_action" value="test" type="submit">Do it</button>
        </Form>
      </div>
    </main>
  );
}

As I said, I can run this exact page and form with a Remix template without errors. If I copy the index route into the Netlify environment, I always get the same error, even though the submission handler is obviously there.

What am I missing here? Tomorrow I have to present my customer with a working version on my Netlify instance. This is not possible with this error.
I’m scared shitless because I can’t find the solution. Btw my actual app also runs without any problems in the classic remix setup.

I hope you can help me here.

Best regards,
Enriko

Sorry for the delay. Could you please share a minimal reproduction repo that we can check on our end?

That’s not necessary at all.
Install your template: npx create-remix@latest --template netlify/remix-template
Inserts a form including a button and an action handler (see above). And then you just have to press the button to get the error in the console.

Sorry, there are several threads that we have to work on and asking for a minimal reproduction is a fairly justified request. If more people make us spend time just creating a reproduction, we would not be able allocate time to actually solve the issue.

Feel free to revert with a repo and we can take a look.

Thank you! I was able to reproduce the issue and also ran some tests without any useful results. I have filed this for the devs to review and would let you know once we hear back from them.

1 Like

Well, I have to launch my project on February 1st. That’s why I switched to Vercel, as everything works smoothly there.

I was very happy with Netlify until migrating to Remix V2. But I couldn’t wait any longer for the bug fix.

I hope you can solve the issue anyways.

Best regards,
Enriko