{"record":{"id":"f257a1485170c8af","repo":"expo/expo","slug":"input-should-not-be-index","errorCode":null,"errorMessage":"Input should not be `index`","messagePattern":"Input should not be `index`","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/@expo/cli/src/start/server/metro/createServerComponentsMiddleware.ts","lineNumber":638,"sourceCode":"}\n\nexport const fileURLToFilePath = (fileURL: string) => {\n  try {\n    return url.fileURLToPath(fileURL);\n  } catch (error) {\n    if (error instanceof TypeError) {\n      throw Error(`Invalid URL: ${fileURL}`, { cause: error });\n    }\n    throw error;\n  }\n};\n\nconst encodeInput = (input: string) => {\n  if (input === '') {\n    return 'index.txt';\n  }\n  if (input === 'index') {\n    throw new Error('Input should not be `index`');\n  }\n  if (input.startsWith('/')) {\n    throw new Error('Input should not start with `/`');\n  }\n  if (input.endsWith('/')) {\n    throw new Error('Input should not end with `/`');\n  }\n  return input + '.txt';\n};\n\nfunction wrapBundle(str: string) {\n  // Skip the metro runtime so debugging is a bit easier.\n  // Replace the __r() call with an export statement.\n  // Use gm to apply to the last require line. This is needed when the bundle has side-effects.\n  return str.replace(/^(__r\\(.*\\);)$/gm, 'module.exports = $1');\n}\n","sourceCodeStart":620,"sourceCodeEnd":655,"githubUrl":"https://github.com/expo/expo/blob/b09195aac27c9e4a63daaf12dcb6f00b6b2e08ee/packages/@expo/cli/src/start/server/metro/createServerComponentsMiddleware.ts#L620-L655","documentation":"Input validation in `encodeInput`, which maps a route's RSC `input` to a `.txt` flight-data filename during static export. The empty string is the canonical index route (`''` -> `index.txt`), so the literal string `'index'` is rejected to prevent an ambiguous/duplicate filename collision under `_flight/<platform>/`.","triggerScenarios":"Thrown at createServerComponentsMiddleware.ts:637 when `exportRoutesAsync` (line 586) calls `encodeInput(input)` and a `buildConfig` entry's `input` is exactly `'index'`. Reached during `expo export` for statically-rendered RSC routes.","commonSituations":"An expo-router version that emits `'index'` instead of `''` for the index route (normalization regression); a custom redirect or generated route whose `input` is set to `'index'`; a route-loading plugin that rewrites the input string.","solutions":["Update `expo-router` and `@expo/cli` to matching versions (input normalization bugs are fixed in patch releases).","Inspect generated routes/redirects for any that set the index path to the literal `'index'` and change them to `''`.","Clear the export cache (`expo export -c`).","If it reproduces on a default app, report with the route tree and SDK versions."],"exampleFix":"// before — custom route generation emits the literal index token\nconst input = route.isIndex ? 'index' : route.path;\n\n// after — use the empty string for the index route as encodeInput expects\nconst input = route.isIndex ? '' : route.path;","handlingStrategy":"validation","validationCode":"// Normalize a route input before passing to encodeInput / exportRoutesAsync.\nfunction normalizeRouteInput(input: string): string {\n  if (input === 'index') return '';\n  return input;\n}\n// const safe = normalizeRouteInput(route.input);","typeGuard":"function isValidRouteInput(input: string): boolean {\n  return input !== 'index' && !input.startsWith('/') && !input.endsWith('/');\n}","tryCatchPattern":null,"preventionTips":["Treat the index route as the empty string, never the literal `'index'`.","Centralize route-input construction so all routes pass through one normalizer.","Add a unit test over your route generator asserting `input !== 'index'`."],"tags":["static-export","rsc","expo-router","validation","routing"],"backgroundTag":null,"analyzedSha":"b09195aac27c9e4a63daaf12dcb6f00b6b2e08ee","analyzedAt":"2026-08-12T15:59:58.304Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}