{"record":{"id":"1e129eecc7e9d512","repo":"remix-run/react-router","slug":"could-not-parse-typescript","errorCode":null,"errorMessage":"Could not parse TypeScript","messagePattern":"Could not parse TypeScript","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/react-router-dev/cli/useJavascript.ts","lineNumber":23,"sourceCode":"import babelPresetTypeScript from \"@babel/preset-typescript\";\nimport prettier from \"prettier\";\n\nexport async function transpile(\n  tsx: string,\n  options: {\n    cwd?: string;\n    filename?: string;\n  } = {},\n): Promise<string> {\n  let mjs = babel.transformSync(tsx, {\n    compact: false,\n    cwd: options.cwd,\n    filename: options.filename,\n    plugins: [babelPluginSyntaxJSX],\n    presets: [[babelPresetTypeScript, { jsx: \"preserve\" }]],\n    retainLines: true,\n  });\n  if (!mjs || !mjs.code) throw new Error(\"Could not parse TypeScript\");\n\n  /**\n   * Babel's `compact` and `retainLines` options are both bad at formatting code.\n   * Use Prettier for nicer formatting.\n   */\n  return await prettier.format(mjs.code, { parser: \"babel\" });\n}\n","sourceCodeStart":5,"sourceCodeEnd":31,"githubUrl":"https://github.com/remix-run/react-router/blob/1fd704a7dabcbe3ae09d7387b460e6acaba30ec1/packages/react-router-dev/cli/useJavascript.ts#L5-L31","documentation":"Thrown by the transpile() helper in useJavascript.ts when babel.transformSync returns null or produces empty code for the input tsx string. The transform uses @babel/preset-typescript (with jsx: 'preserve') plus @babel/plugin-syntax-jsx. An empty result means Babel could not produce output — typically because the input is empty, the filename/cwd options resolve to a non-existent directory, or a Babel internals failure occurred.","triggerScenarios":"Calling transpile('') or transpile(undefined as any); passing options.cwd or options.filename pointing at a missing path so Babel cannot resolve config/plugins; a Babel plugin/preset version mismatch where transformSync throws internally but is caught upstream leaving mjs null.","commonSituations":"An empty routes.ts or entry file passed for JS conversion during build; a stale node_modules with mismatched @babel/core and preset-typescript versions; a build script invoking transpile before the source file is written; misconfigured monorepo hoisting breaking Babel resolution.","solutions":["Ensure the input string is non-empty and actually TypeScript/JSX before calling transpile.","Verify @babel/core, @babel/preset-typescript, and @babel/plugin-syntax-jsx are installed and version-compatible (reinstall node_modules).","If passing options.cwd/options.filename, confirm the directory exists and contains the relevant babel config or that none is required.","Run the build with verbose output to capture any swallowed Babel exception preceding the null result.","Wrap the call site in a try/catch and log babel.transformSync's return value to diagnose why code is empty."],"exampleFix":"// before\nconst js = await transpile(maybeEmptyString, { cwd: '/missing' });\n// after\ndefensiveTrimAndCheck();\nif (!tsx.trim()) throw new Error('nothing to transpile');\nconst js = await transpile(tsx, { cwd: process.cwd(), filename: 'entry.tsx' });","handlingStrategy":"validation","validationCode":"import * as babel from '@babel/core';\nfunction canTranspile(tsx: string, cwd?: string, filename?: string): boolean {\n  if (!tsx || !tsx.trim()) return false;\n  try {\n    const r = babel.transformSync(tsx, { cwd, filename, compact: false,\n      plugins: [require('@babel/plugin-syntax-jsx')],\n      presets: [[require('@babel/preset-typescript'), { jsx: 'preserve' }]],\n      retainLines: true });\n    return !!r && !!r.code;\n  } catch { return false; }\n}\n// if (!canTranspile(source)) surface a clearer error before continuing","typeGuard":"function isNonEmptyString(s: unknown): s is string {\n  return typeof s === 'string' && s.trim().length > 0;\n}","tryCatchPattern":"try {\n  const js = await transpile(tsx, { cwd, filename });\n} catch (e) {\n  if (/Could not parse TypeScript/.test(String((e as Error).message))) {\n    // log tsx length, cwd, filename; verify @babel/* versions; fail build with context\n    throw new Error(`transpile() returned no output for ${filename ?? '<inline>'}`);\n  }\n  throw e;\n}","preventionTips":["Never pass empty/whitespace-only strings to transpile().","Pin and reinstall @babel/core, @babel/preset-typescript, @babel/plugin-syntax-jsx together.","Resolve cwd/filename to existing directories before calling.","Add a unit test that transpiles a known snippet to catch environment regressions."],"tags":["build","babel","typescript","react-router-dev"],"backgroundTag":null,"analyzedSha":"1fd704a7dabcbe3ae09d7387b460e6acaba30ec1","analyzedAt":"2026-08-12T13:54:57.804Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}