{"record":{"id":"17ded354bdadb98c","repo":"facebook/react","slug":"file-blob-fields-are-not-yet-supported-in-progress","errorCode":null,"errorMessage":"File/Blob fields are not yet supported in progressive forms. Will fallback to client hydration.","messagePattern":"File/Blob fields are not yet supported in progressive forms\\. Will fallback to client hydration\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"packages/react-dom-bindings/src/server/ReactFizzConfigDOM.js","lineNumber":1424,"sourceCode":"  validateAdditionalFormField(value, key);\n  pushStringAttribute(target, 'name', key);\n  pushStringAttribute(target, 'value', value);\n  target.push(endOfStartTagSelfClosing);\n}\n\nfunction pushAdditionalFormFields(\n  target: Array<Chunk | PrecomputedChunk>,\n  formData: void | null | FormData,\n) {\n  if (formData != null) {\n    // $FlowFixMe[prop-missing]: FormData has forEach.\n    formData.forEach(pushAdditionalFormField, target);\n  }\n}\n\nfunction validateAdditionalFormField(value: string | File, key: string): void {\n  if (typeof value !== 'string') {\n    throw new Error(\n      'File/Blob fields are not yet supported in progressive forms. ' +\n        'Will fallback to client hydration.',\n    );\n  }\n}\n\nfunction validateAdditionalFormFields(formData: void | null | FormData) {\n  if (formData != null) {\n    // $FlowFixMe[prop-missing]: FormData has forEach.\n    formData.forEach(validateAdditionalFormField);\n  }\n  return formData;\n}\n\nfunction getCustomFormFields(\n  resumableState: ResumableState,\n  formAction: any,\n): null | ReactCustomFormAction {","sourceCodeStart":1406,"sourceCodeEnd":1442,"githubUrl":"https://github.com/facebook/react/blob/eafeac097ba51e1eab809c07102126bd5f8e5425/packages/react-dom-bindings/src/server/ReactFizzConfigDOM.js#L1406-L1442","documentation":"React's Fizz server renderer validates the FormData attached to a form action (via the action's $$FORM_ACTION metadata, e.g. bound arguments of a Server Action) when it tries to serialize the form for progressive enhancement (a form that works before JS loads). Hidden inputs can only encode string values, so any File/Blob entry in that FormData fails validation. The throw happens inside getCustomFormFields, which catches it, logs 'Failed to serialize an action for progressive enhancement' in DEV, and silently downgrades the form to client-hydration-only replay, so the render does not crash.","triggerScenarios":"Rendering <form action={fn}> during SSR where fn is a server action whose $$FORM_ACTION(prefix) returns customFields.data containing a File or Blob value — typically a server action bound (via .bind or a closure) to a FormData that came from a file input (e.g. request.formData() with type=\"file\" fields), used with <form action> or useActionState progressive enhancement.","commonSituations":"Next.js App Router or RSC apps with file-upload forms built on server actions; binding a captured FormData (which includes files) into an action; custom createServerReference/registerServerReference implementations whose $$FORM_ACTION returns file entries. The page still works after hydration, so the only visible symptom is the DEV console.error and forms that do nothing before JS loads.","solutions":["Do not bind File/Blob entries into the server action — extract only serializable string values (filenames, ids, text fields) into the closure/bind args","Read files from the submitted FormData inside the action (form inputs are transmitted with the form anyway) instead of pre-binding them","If a file upload must work without JS, point the form at a plain route handler or API endpoint instead of a server action","In a custom $$FORM_ACTION implementation, filter data down to string entries before returning it"],"exampleFix":"// before\nconst action = uploadAction.bind(null, formDataWithFiles); // FormData contains File entries\n<form action={action}>...</form>\n\n// after: bind only strings; read files from the submission itself\nconst action = uploadAction.bind(null, formDataWithFiles.get('docName'));\n<form action={action}>\n  <input type=\"file\" name=\"doc\" />\n</form>","handlingStrategy":"validation","validationCode":"function hasOnlyStringFields(formData: FormData): boolean {\n  let ok = true;\n  formData.forEach((value) => {\n    if (typeof value !== 'string') ok = false;\n  });\n  return ok;\n}\n// before binding: \n// const bound = hasOnlyStringFields(fd) ? uploadAction.bind(null, fd) : uploadAction;","typeGuard":"function isFileEntry(v: FormDataEntryValue): v is File {\n  return typeof v !== 'string'; // File/Blob is the only non-string FormDataEntryValue\n}","tryCatchPattern":"// Not applicable to userland: React catches this internally in getCustomFormFields and only logs a DEV console.error ('Failed to serialize an action for progressive enhancement'), then falls back to client replay.","preventionTips":["Never bind File or Blob values into server actions; bind only strings, numbers, and serializable primitives","Read file inputs from the FormData the browser submits, not from closure state","Test forms with JavaScript disabled to detect lost progressive enhancement early","In custom $$FORM_ACTION implementations, filter data to string entries before returning"],"tags":["server-actions","form-data","file-upload","progressive-enhancement","ssr"],"backgroundTag":"server-action-serialization-failed","analyzedSha":"eafeac097ba51e1eab809c07102126bd5f8e5425","analyzedAt":"2026-08-21T22:01:08.818Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}