{"record":{"id":"710ede2ad06c0883","repo":"shadcn-ui/ui","slug":"failed-to-transform-jsx","errorCode":null,"errorMessage":"Failed to transform JSX","messagePattern":"Failed to transform JSX","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/shadcn/src/utils/transformers/transform-jsx.ts","lineNumber":91,"sourceCode":"\n  const ast = recast.parse(output, {\n    parser: {\n      parse: (code: string) => {\n        return parse(code, PARSE_OPTIONS)\n      },\n    },\n  })\n\n  const result = transformFromAstSync(ast, output, {\n    cloneInputAst: false,\n    code: false,\n    ast: true,\n    plugins: [transformTypescript],\n    configFile: false,\n  })\n\n  if (!result || !result.ast) {\n    throw new Error(\"Failed to transform JSX\")\n  }\n\n  return recast.print(result.ast).code\n}\n","sourceCodeStart":73,"sourceCodeEnd":96,"githubUrl":"https://github.com/shadcn-ui/ui/blob/efac5987074af84ece57c367c6dd83387b967022/packages/shadcn/src/utils/transformers/transform-jsx.ts#L73-L96","documentation":"Thrown by transformJsx when babel's transformFromAstSync returns no result or a result without an .ast property. transformJsx runs only when config.tsx is false (JS project): it parses the source with babel, then strips TypeScript types via the transformTypescript plugin to emit JS. A null result means babel could not produce an AST, usually due to unsupported/invalid syntax.","triggerScenarios":"Adding a registry file to a non-TSX (JS) project; transformJsx parses file.content with babel parser (PARSE_OPTIONS including TypeScript + JSX + many plugins), runs transformFromAstSync with transformTypescript, and checks `if (!result || !result.ast)`.","commonSituations":"Registry file uses syntax babel's configured plugins cannot parse (experimental TC39 proposals, decorators stage mismatch, very new TS syntax); corrupted/truncated file content; babel/core version mismatch in the consumer's node_modules.","solutions":["Set \"tsx\": true in components.json if your project is TypeScript — this skips the JS transform entirely.","If you must stay on JS, simplify the offending registry file's syntax to widely-supported JS/JSX.","Ensure @babel/core, @babel/preset-typescript, and recast are installed at compatible versions.","Check the file content for truncation or encoding issues, then retry."],"exampleFix":"// components.json (before) — JS project forces transform\n{ \"tsx\": false }\n// after — if project is TS, enable tsx to skip transform\n{ \"tsx\": true }","handlingStrategy":"fallback","validationCode":"// before installing into a JS project, sanity-parse each file\nimport { parse } from \"@babel/parser\"\ntry {\n  parse(file.content, { sourceType: \"module\", plugins: [\"jsx\", \"typescript\"] })\n} catch (e) {\n  throw new Error(`file ${file.path} cannot be parsed for JS transform`)\n}","typeGuard":"const isTransformableJsx = (source: string): boolean => {\n  try { parse(source, PARSE_OPTIONS); return true } catch { return false }\n}","tryCatchPattern":"try {\n  await transformJsx({ sourceFile, config })\n} catch (e) {\n  if (e instanceof Error && /Failed to transform JSX/.test(e.message)) {\n    // fall back to keeping the file as-is or skip the JS transform\n  }\n  throw e\n}","preventionTips":["Prefer \"tsx\": true in components.json for TypeScript projects to skip this transform.","Restrict registry file syntax to stable JS/JSX/TS supported by the bundled babel.","Keep @babel/core and @babel/preset-typescript versions aligned with shadcn.","Pre-validate registry files with the same babel parser options."],"tags":["transform","babel","jsx","build"],"backgroundTag":null,"analyzedSha":"efac5987074af84ece57c367c6dd83387b967022","analyzedAt":"2026-08-12T05:00:50.218Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}