remix-run / remix

Build Better Websites. Create modern, resilient user experiences with web fundamentals.
https://remix.run
MIT License
29.96k stars 2.53k forks source link

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

Closed jonybekov closed 1 year ago

jonybekov commented 2 years ago

What version of Remix are you using?

1.1.3

Steps to Reproduce

Expected Behavior

Form should be submitted successfully.

Actual Behavior

image

kiliman commented 2 years ago

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

ricevind commented 2 years ago

@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

sergiodxa commented 2 years ago

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.

jonybekov commented 2 years ago

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.

jgalianoz commented 2 years ago

I have the same problem but in vercel.

image
car-r commented 1 year ago

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

sethcalebweeks commented 1 year ago

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 commented 1 year ago

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.

ryanflorence commented 1 year ago

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