{"record":{"id":"99d9c7bf5e2a4bf4","repo":"facebook/react","slug":"582","errorCode":"582","errorMessage":"Referenced Blob is not a Blob.","messagePattern":"Referenced Blob is not a Blob\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/react-server/src/ReactFlightReplyServer.js","lineNumber":1886,"sourceCode":"          DataView,\n          1,\n          obj,\n          key,\n          arrayRoot,\n        );\n      case 'B': {\n        // Blob\n        const id = parseInt(value.slice(2), 16);\n        const prefix = response._prefix;\n        const blobKey = prefix + id;\n        // We should have this backingEntry in the store already because we emitted\n        // it before referencing it. It should be a Blob.\n        const backingEntry: Blob = getBackingEntry(\n          response._formData,\n          blobKey,\n        ) as any;\n        if (!(backingEntry instanceof Blob)) {\n          throw new Error('Referenced Blob is not a Blob.');\n        }\n        return backingEntry;\n      }\n      case 'R': {\n        return parseReadableStream(response, value, undefined, obj, key);\n      }\n      case 'r': {\n        return parseReadableStream(response, value, 'bytes', obj, key);\n      }\n      case 'X': {\n        return parseAsyncIterable(response, value, false, obj, key);\n      }\n      case 'x': {\n        return parseAsyncIterable(response, value, true, obj, key);\n      }\n    }\n    // We assume that anything else is a reference ID.\n    const ref = value.slice(1);","sourceCodeStart":1868,"sourceCodeEnd":1904,"githubUrl":"https://github.com/facebook/react/blob/eafeac097ba51e1eab809c07102126bd5f8e5425/packages/react-server/src/ReactFlightReplyServer.js#L1868-L1904","documentation":"When decoding a client reply, a 'B' row points at a backing entry that was previously uploaded as a real FormData part and is referenced by id. The decoder fetches that entry and requires it to be a Blob/File. If the entry is absent or has been replaced by a string — the classic symptom of re-encoding the FormData through JSON — the instanceof check fails and this error is thrown.","triggerScenarios":"decodeReply(formData) where the file row references an entry key that is missing or holds a string; rebuilding FormData via Object.fromEntries()/JSON round-trip before decoding; File objects from a different realm/implementation (two undici versions, mixed polyfills) so the instanceof Blob check fails even for real files.","commonSituations":"API gateways or middleware that re-serialize request bodies; selectively copying form fields and dropping the file key; manually constructed FormData in tests; Node runtimes with multiple File globals.","solutions":["Forward the original request FormData unmodified to decodeReply (or use decodeReplyFromBusboy for multipart streams).","If you must rebuild FormData, append the original File objects — not strings — under their original keys.","Ensure a single Blob/File implementation is in play (pin one undici version, Node >= 20) so the instanceof check succeeds."],"exampleFix":"// before — files flattened to strings\nconst flat = Object.fromEntries(formData);\nconst rebuilt = new FormData();\nfor (const [k, v] of Object.entries(flat)) rebuilt.append(k, v);\nconst args = await decodeReply(rebuilt);\n\n// after — decode the original FormData\nconst args = await decodeReply(formData);","handlingStrategy":"type-guard","validationCode":"// Verify every expected file entry survived transport as a Blob, cross-realm safe.\nexport function assertIntactFileEntries(formData: FormData, fileKeys: string[]) {\n  for (const key of fileKeys) {\n    const v = formData.get(key);\n    if (v !== null && !isBlobLike(v)) throw new Error(`entry ${key} is no longer a Blob`);\n  }\n}","typeGuard":"// Duck-typed guard: survives cross-realm instances where instanceof Blob fails.\nexport function isBlobLike(v: unknown): v is Blob {\n  if (typeof v !== 'object' || v === null) return false;\n  const o = v as any;\n  return typeof o.stream === 'function' && typeof o.arrayBuffer === 'function' && typeof o.size === 'number';\n}","tryCatchPattern":"try {\n  const args = await decodeReply(formData);\n} catch (e) {\n  if (/not a Blob/.test(String((e as Error)?.message))) {\n    return badRequest('upload payload corrupted in transit');\n  }\n  throw e;\n}","preventionTips":["Never round-trip action FormData through JSON or Object.fromEntries.","Use decodeReplyFromBusboy when consuming multipart directly from Node streams.","Pin one undici/File implementation; avoid multiple Blob globals in the process."],"tags":["blob","file-upload","form-data","server-actions","serialization"],"backgroundTag":"form-data-decoding-failed","analyzedSha":"eafeac097ba51e1eab809c07102126bd5f8e5425","analyzedAt":"2026-08-21T22:01:08.818Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}