remix icon indicating copy to clipboard operation
remix copied to clipboard

Cannot submit netlify forms. Error: Unexpected Server Error at handleDataRequest...

Open jonybekov opened this issue 3 years ago • 8 comments

What version of Remix are you using?

1.1.3

Steps to Reproduce

  • Create form using remix's Form component.
  • Add attributes name="contact-form" action="/" method="post" className="w-full" data-netlify="true" .
  • Add hidden input to form as explained here
  • Add action handler to index page.
export async function action({ request }: any) {
  const form = await request.formData();

  await fetch("/", {
    method: "POST",
    headers: { "Content-Type": "application/x-www-form-urlencoded" },
    body: form,
  });

  return redirect("/submitted");
}

Expected Behavior

Form should be submitted successfully.

Actual Behavior

image

jonybekov avatar Mar 01 '22 15:03 jonybekov

Looks like your action function is reposting to the same route. What are you trying to do?

kiliman avatar Mar 08 '22 17:03 kiliman

@jonybekov

I made remix and netlify forms work (with some drawbacks)

  1. per netlify docs add [your-name].html file with <form netlify> element and inputs you are using to public folder to let netlify bots register your form
  2. create <Form> element to your page and create corresponding actionFunction
  • in your action function don't set { "Content-Type": "application/x-www-form-urlencoded" }
  • use url for form submission fetch(${process.env.URL!}/form) where form is arbitrary name
  1. in netlify.toml add
[[redirects]]
  from = "/form"
  to = "/"
  status = 200

The idea is to use remix action handler which is run inside netlify function to send form submission. process.env.URL is environment variable which has your production site's url (i could not find env variable with actual current deploy url e.g. when having preview build) which i consider a drawback of this solution. Stil default remix setup for netlify has

  from = "/*"
  to = "/.netlify/functions/server"
  status = 200 

which will catch your form submission (even when done from action) but adding ABOVE this rule

[[redirects]]
     from = "/form"
     to = "/"
     status = 200

will forward requests to your_url/form to your_url and bypass remix serverless function

ricevind avatar Mar 09 '22 22:03 ricevind

You can't do a fetch to a URL without host and protocol server-side so fetch("/") will not work. You need to know the full URL.

sergiodxa avatar Mar 09 '22 23:03 sergiodxa

Looks like your action function is reposting to the same route. What are you trying to do?

I am trying to send a form data to netlify forms. In the docs it's said that ajax requests should be sent to root page.

jonybekov avatar Mar 10 '22 04:03 jonybekov

I have the same problem but in vercel. image

jgalianoz avatar Sep 05 '22 17:09 jgalianoz

Screen Shot 2022-12-09 at 8 33 31 PM I have the same issue on Fly.io

car-r avatar Dec 10 '22 03:12 car-r

Same issue on AWS Architect. Here is my code:

import { Form, useActionData, useSubmit } from "@remix-run/react";
import type { ActionArgs } from "@remix-run/node";
import { json } from "@remix-run/node";
import { search } from "~/deepgram.server";
import invariant from "tiny-invariant";

export async function action({ request }: ActionArgs) {
  const formData = await request.formData();

  const name = formData.get("name");
  const privacyCode = formData.get("privacyCode");
  const recording = formData.get("recording");

  const errors = {
    name: name ? null : "Name is required",
    privacyCode: privacyCode ? null : "Privacy Code is required",
    recording: recording ? null : "Recording is required",
  };
  invariant(typeof name === "string", "name must be a string");
  invariant(typeof privacyCode === "string", "privacyCode must be a string");

  const hasErrors = Object.values(errors).some((errorMessage) => errorMessage);

  if (hasErrors) {
    return json({ errors });
  } else {
    const buffer = Buffer.from(await recording.arrayBuffer(), "base64");
    const confidence = await search(buffer, name, privacyCode);
    return json({
      confidence,
    });
  }
}

export default function Index() {
  const actionData = useActionData<typeof action>();
  const submit = useSubmit();

  const handleSubmit = (event: any) => {
    event.preventDefault();
    const formData = new FormData(event.currentTarget);
    submit(formData, {
      method: "post",
      encType: "multipart/form-data",
    });
  };

  return (
    <main className="relative min-h-screen bg-white sm:flex sm:items-center sm:justify-center">
      <Form method="post" encType="multipart/form-data" onSubmit={handleSubmit}>
        <label className="block">
          Name
          <input name="name" id="name" />
          {actionData?.errors?.name ? (
            <em className="text-red-600">{actionData?.errors?.name}</em>
          ) : null}
          {actionData?.confidence?.name ? (
            <span>{actionData?.confidence?.name}</span>
          ) : null}
        </label>
        <label className="block">
          Privacy Code
          <input name="privacyCode" id="privacyCode" />
          {actionData?.errors?.privacyCode ? (
            <em className="text-red-600">{actionData?.errors?.privacyCode}</em>
          ) : null}
          {actionData?.confidence?.privacyCode ? (
            <span>{actionData?.confidence?.privacyCode}</span>
          ) : null}
        </label>
        <label className="block">
          Recording
          <input
            type="file"
            accept="audio/*"
            capture
            name="recording"
            id="recording"
          />
        </label>
        <button type="submit">Submit</button>
      </Form>
    </main>
  );
}

sethcalebweeks avatar Jan 16 '23 17:01 sethcalebweeks

Update: I discovered that there was actually an error being thrown on the server. (Due to a missing environment variable, but presumably any error would have caused the same result). Perhaps there is a better way of letting these error messages get through when they happen? Or at least some better error message that gives an idea of what went wrong.

sethcalebweeks avatar Jan 16 '23 17:01 sethcalebweeks

Server logs should have the real error, we remove the stack in production so nothing sensitive is revealed to clients.

ryanflorence avatar Aug 08 '23 21:08 ryanflorence