← Home ← Codex ← DEBT ← Engine
Browse by Category
+ added · updated 7d
← Back to glossary

FormData API

JavaScript ES2015 Intermediate
debt(d7/e1/b3/t9)
d7 Detectability Operational debt — how invisible misuse is to your safety net

Closest to 'only careful code review or runtime testing' (d7). The detection_hints note that automated detection is 'no' and ESLint is listed but cannot catch the semantic mistake of manually setting Content-Type or forgetting CSRF appends without a highly specific custom rule. The bug manifests as a broken upload at runtime — the request goes out but PHP receives nothing, which requires runtime testing or careful review to catch.

e1 Effort Remediation debt — work required to fix once spotted

Closest to 'one-line patch or single-call swap' (e1). The quick_fix is exactly one change: remove the manually-set Content-Type header (or add one FormData.append call for CSRF). No refactoring needed — it's a single-line deletion or addition at the call site.

b3 Burden Structural debt — long-term weight of choosing wrong

Closest to 'localised tax' (b3). The applies_to scope is web contexts only, and the pattern is confined to individual form-submission call sites. Each affected fetch/XHR call needs the correct pattern, but the rest of the codebase is unaffected. It doesn't impose a cross-cutting architectural burden.

t9 Trap Cognitive debt — how counter-intuitive correct behaviour is

Closest to 'catastrophic trap — the obvious way is always wrong' (t9). The misconception field explicitly states that the 'obvious' developer action — manually setting Content-Type: multipart/form-data — is exactly wrong and silently breaks the upload by omitting the browser-generated boundary parameter. This directly contradicts how Content-Type headers work everywhere else (where you set them explicitly), making it a classic t9 trap.

About DEBT scoring →

Also Known As

FormData multipart form data AJAX file upload

TL;DR

FormData constructs key-value pairs from HTML forms for AJAX submission to PHP backends — supports file uploads without page reload.

Explanation

FormData mirrors PHP's $_POST and $_FILES. new FormData(formElement) captures all fields automatically. Append extra data with .append(). Submit via fetch() with no Content-Type header — the browser sets multipart/form-data with the correct boundary automatically. PHP reads files via $_FILES and fields via $_POST as normal. Never set Content-Type: application/json when sending FormData — it breaks multipart encoding.

Common Misconception

You must set Content-Type: multipart/form-data manually when using FormData — setting it manually omits the boundary parameter and breaks the upload; let the browser set it automatically.

Why It Matters

FormData lets you submit PHP forms including file uploads entirely via JavaScript without page reload, keeping PHP's server-side validation and file handling unchanged.

Common Mistakes

  • Setting Content-Type header manually when using FormData
  • Not appending CSRF token to FormData before submit
  • Using JSON.stringify on FormData — it serialises to empty object

Code Examples

✗ Vulnerable
// Wrong — breaks multipart boundary:
fetch('/upload.php', {
    method: 'POST',
    headers: { 'Content-Type': 'multipart/form-data' }, // DO NOT SET
    body: new FormData(form)
});
✓ Fixed
const fd = new FormData(document.querySelector('#upload-form'));
fd.append('_token', document.querySelector('meta[name=csrf-token]').content);

// No Content-Type header — browser sets it correctly:
const res = await fetch('/upload.php', { method: 'POST', body: fd });
const data = await res.json();
// PHP reads normally: $_POST['field'], $_FILES['file']

Added 17 Mar 2026
Edited 22 Mar 2026
Views 85
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
0 pings S 2 pings M 0 pings T 0 pings W 0 pings T 0 pings F 1 ping S 1 ping S 0 pings M 0 pings T 1 ping W 0 pings T 2 pings F 0 pings S 0 pings S 1 ping M 0 pings T 0 pings W 1 ping T 0 pings F 1 ping S 1 ping S 0 pings M 0 pings T 0 pings W 0 pings T 1 ping F 2 pings S 1 ping S 0 pings M
No pings yet today
PetalBot 1
Amazonbot 9 Perplexity 8 Scrapy 7 PetalBot 6 ChatGPT 5 Unknown AI 5 Ahrefs 5 Google 4 Brave Search 3 Claude 2 Majestic 1 Meta AI 1 Sogou 1 Twitter/X 1 Applebot 1 Bing 1
crawler 56 crawler_json 3 pre-tracking 1
🧱 FUNDAMENTALS — new to this? Start with the ground floor.
JavaScript javascript The programming language of the browser — it reads and modifies the page (the DOM), reacts to user events, and fetches data without reloading.

JavaScript is the only language browsers execute, so every interactive behaviour on the web goes through it. Its two defining traits — single-threaded event loop and loose typing (== coercion) — explain the majority of both its bugs and its design patterns.

💡 Default to const, use === always, and reach for let only when a value genuinely reassigns.

Ask Codex about JavaScript →
DEV INTEL Tools & Severity
🟡 Medium ⚙ Fix effort: Low
⚡ Quick Fix
new FormData(formEl) + fetch with no Content-Type header — PHP receives $_POST and $_FILES as normal
📦 Applies To
javascript ES2015 web
🔗 Prerequisites
🔍 Detection Hints
fetch POST with FormData and manually set Content-Type header; not appending CSRF token to FormData
Auto-detectable: ✗ No eslint
⚠ Related Problems
🤖 AI Agent
Confidence: Medium False Positives: Medium ✗ Manual fix Fix: Medium Context: Function Tests: Update
CWE-352


✓ schema.org compliant