{"record":{"id":"e9da8a7c15069448","repo":"facebook/react","slug":"expected-source-to-have-been-transformed-to-a-stri","errorCode":null,"errorMessage":"Expected source to have been transformed to a string.","messagePattern":"Expected source to have been transformed to a string\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/react-server-dom-esm/src/ReactFlightESMNodeLoader.js","lineNumber":772,"sourceCode":"  }\n\n  return transformServerModule(source, program, url, sourceMap, loader);\n}\n\nexport async function transformSource(\n  source: Source,\n  context: TransformSourceContext,\n  defaultTransformSource: TransformSourceFunction,\n): Promise<{source: Source}> {\n  const transformed = await defaultTransformSource(\n    source,\n    context,\n    defaultTransformSource,\n  );\n  if (context.format === 'module') {\n    const transformedSource = transformed.source;\n    if (typeof transformedSource !== 'string') {\n      throw new Error('Expected source to have been transformed to a string.');\n    }\n    const newSrc = await transformModuleIfNeeded(\n      transformedSource,\n      context.url,\n      (url: string, ctx: LoadContext, defaultLoad: LoadFunction) => {\n        return loadClientImport(url, defaultTransformSource);\n      },\n    );\n    return {source: newSrc};\n  }\n  return transformed;\n}\n\nexport async function load(\n  url: string,\n  context: LoadContext,\n  defaultLoad: LoadFunction,\n): Promise<{format: string, shortCircuit?: boolean, source: Source}> {","sourceCodeStart":754,"sourceCodeEnd":790,"githubUrl":"https://github.com/facebook/react/blob/eafeac097ba51e1eab809c07102126bd5f8e5425/packages/react-server-dom-esm/src/ReactFlightESMNodeLoader.js#L754-L790","documentation":"In the loader's transformSource hook, the source returned by defaultTransformSource for format 'module' must be a plain string, because React parses it (directive scan, client-import rewriting) with its own tooling. Node permits hook results of string, ArrayBuffer, or Uint8Array; any binary representation that reaches this point fails the invariant.","triggerScenarios":"A loader earlier in the chain returns {format: 'module', source: Buffer|Uint8Array|ArrayBuffer}, or the module comes from a scheme whose source Node produces as binary (for example network imports under --experimental-network-imports), and it flows into transformSource.","commonSituations":"Chaining asset or transpilation loaders (tsx, esbuild, CSS loaders) that return Buffers; Node major upgrades changing default source types; data: or http: module imports.","solutions":["Fix the earlier loader so JS module sources are returned as utf-8 strings","Insert a small adapter hook before React's that decodes binary sources with new TextDecoder().decode(source) for format 'module'","Drop --experimental-network-imports or other schemes that yield binary module sources"],"exampleFix":"// before — chained loader hands React a Buffer for module format\nexport async function transformSource(source, context, dflt) {\n  const r = await dflt(source, context, dflt);\n  return r; // source is a Uint8Array here\n}\n\n// after — always hand React a string for module format\nexport async function transformSource(source, context, dflt) {\n  const r = await dflt(source, context, dflt);\n  if (context.format === 'module' && typeof r.source !== 'string') {\n    return {...r, source: new TextDecoder().decode(r.source)};\n  }\n  return r;\n}","handlingStrategy":"validation","validationCode":"// in any chained hook you control, enforce the invariant before React's hook runs\nexport async function transformSource(source, context, dflt) {\n  const r = await dflt(source, context, dflt);\n  if (context.format === 'module' && typeof r.source !== 'string') {\n    return {...r, source: new TextDecoder().decode(r.source)};\n  }\n  return r;\n}","typeGuard":"export function isStringModuleSource(result) {\n  return result.format !== 'module' || typeof result.source === 'string';\n}","tryCatchPattern":"try {\n  await import(url);\n} catch (e) {\n  if (/transformed to a string/.test(e.message)) {\n    console.error('A chained loader returned binary source for', url);\n  }\n  throw e;\n}","preventionTips":["Keep module-format sources as utf-8 strings across your whole loader chain","Decode binary sources at the boundary where they enter the chain","Avoid experimental network imports in RSC builds"],"tags":["node-esm","module-loader","buffer","react-server-components"],"backgroundTag":"esm-loader-source-not-string","analyzedSha":"eafeac097ba51e1eab809c07102126bd5f8e5425","analyzedAt":"2026-08-21T22:01:08.818Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}