# Diagnose Netlify Forms: not detected, submissions missing, or 404 on submit
Use this when a Netlify-handled form doesn't work. There are three distinct
failure modes with different fixes, so classify first: **(A)** the form was
never registered (detection), **(B)** the form is registered but submissions
don't appear, **(C)** submissions return 404.
## 1. Is the form registered at all?
Form detection runs during post-processing of each deploy: Netlify scans the
*built, published HTML* for `<form>` elements carrying `data-netlify="true"`
or the bare `netlify` attribute, and registers each one under its `name`
attribute. Check the site's Forms tab in the Netlify UI for your form's name.
- **Name absent → failure mode A (detection).** Go to section 2.
- **Name present → failure mode B or C.** Go to section 3.
## 2. Mode A: the form was never detected
Causes, in likelihood order:
1. **The form isn't in the built HTML.** Detection only sees the static HTML
produced at build time. If the form is rendered client-side (React, Vue,
Next.js, Astro, SvelteKit), the parser never sees it. Fix: add a static
skeleton file in the publish directory (conventionally
`public/__forms.html`) containing a hidden copy of every form, with exactly
the same `name`, field names, and honeypot field:
```html
<form name="contact" data-netlify="true" netlify-honeypot="bot-field" hidden>
<input type="hidden" name="form-name" value="contact" />
<input type="text" name="name" />
<input type="email" name="email" />
<textarea name="message"></textarea>
<input name="bot-field" />
</form>
```
The `hidden` attribute keeps it invisible; the file must ship in the publish
directory. One skeleton file can hold all of your forms.
2. **Missing or mismatched attributes.** The form needs `data-netlify="true"`
(or bare `netlify`) *and* a `name` attribute. On AJAX posts, the request
body must also carry a hidden input whose `name` is `form-name` and whose
`value` exactly equals the form's `name`:
```html
<form name="contact" method="POST" data-netlify="true">
<input type="hidden" name="form-name" value="contact" />
<!-- ... fields ... -->
</form>
```
3. **Detection was off, or the fix hasn't been deployed.** Form detection must
be enabled in site settings, and every markup fix needs a new deploy —
detection only runs on the latest deploy's HTML.
After redeploying, confirm the form name appears in the Forms tab *before*
testing again. Submissions made before registration are lost.
## 3. Mode B: the form is registered, but submissions are missing
1. **Check the spam tab first.** Netlify filters submissions through Akismet.
Legitimate-looking test submissions get flagged constantly: sending from a
throwaway address, one-line messages, or rapid-fire tests from one IP are
classic spam signals. Test with a real email address and a realistic
message, then look in the Spam list and mark it verified.
2. **Check the `form-name` hidden input on AJAX submissions.** Without
`<input type="hidden" name="form-name" value="[exact form name]">` in the
POST body, Netlify can't route the submission and it silently fails.
3. **Check field names against the registered form.** Netlify validates
submitted field names against the registered form definition — a renamed
input in your component won't appear where you expect. (The UI shows only
the fields from the last deployed form version; old submissions keep their
data but won't show the new fields. Mark fields hidden instead of deleting
them if you need continuity.)
4. **Don't hand-roll reCAPTCHA next to Netlify's.** If you're doing custom
reCAPTCHA verification inside your own function and POSTing to the form
endpoint yourself, Netlify's form processing may never run. Use Netlify's
own reCAPTCHA integration (`data-netlify-recaptcha="true"` plus the
recaptcha div) instead of a parallel custom flow.
## 4. Mode C: 404 on submit
POSTing to a form name that isn't registered returns 404 — and so does
posting after the form was deleted (deletion is permanent; export a CSV
first). Fix: go back to section 2, register the form, redeploy, and confirm
it before resubmitting. For AJAX, POST to `/` (or the page's own path) with
`Content-Type: application/x-www-form-urlencoded`.
## 5. Checklist
1. Forms tab: is the name listed? No → detection problem (built HTML, skeleton
file, attributes, redeploy).
2. Listed but nothing arrives → spam tab (Akismet), then the `form-name`
hidden input, then field-name match.
3. 404 → the form was deleted or never registered; register and redeploy.
4. Every markup fix requires a new deploy — detection only sees the latest
build's HTML.
5. Test with a real email and realistic content, not throwaway one-liners.