{"record":{"id":"b5d98304d2504558","repo":"withastro/astro","slug":"missingmiddlewareforinternationalization","errorCode":"MissingMiddlewareForInternationalization","errorMessage":"Your configuration setting `i18n.routing: 'manual'` requires you to provide your own i18n `middleware` file.","messagePattern":"Your configuration setting `i18n\\.routing: 'manual'` requires you to provide your own i18n `middleware` file\\.","errorType":"exception","errorClass":"AstroError","httpStatus":null,"severity":"error","filePath":"packages/astro/src/core/middleware/vite-plugin.ts","lineNumber":80,"sourceCode":"\t\t\t\tuserMiddlewareIsPresent = !!middlewareId;\n\t\t\t\tif (middlewareId) {\n\t\t\t\t\tresolvedMiddlewareId = middlewareId.id;\n\t\t\t\t\treturn MIDDLEWARE_RESOLVED_MODULE_ID;\n\t\t\t\t} else if (hasIntegrationMiddleware) {\n\t\t\t\t\treturn MIDDLEWARE_RESOLVED_MODULE_ID;\n\t\t\t\t} else {\n\t\t\t\t\treturn NOOP_MIDDLEWARE;\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t\tload: {\n\t\t\tfilter: {\n\t\t\t\tid: new RegExp(`^(${NOOP_MIDDLEWARE}|${MIDDLEWARE_RESOLVED_MODULE_ID})$`),\n\t\t\t},\n\t\t\tasync handler(id) {\n\t\t\t\tif (id === NOOP_MIDDLEWARE) {\n\t\t\t\t\tif (!userMiddlewareIsPresent && settings.config.i18n?.routing === 'manual') {\n\t\t\t\t\t\tthrow new AstroError(MissingMiddlewareForInternationalization);\n\t\t\t\t\t}\n\t\t\t\t\treturn { code: 'export const onRequest = (_, next) => next()' };\n\t\t\t\t}\n\t\t\t\tif (id === MIDDLEWARE_RESOLVED_MODULE_ID) {\n\t\t\t\t\tif (!userMiddlewareIsPresent && settings.config.i18n?.routing === 'manual') {\n\t\t\t\t\t\tthrow new AstroError(MissingMiddlewareForInternationalization);\n\t\t\t\t\t}\n\n\t\t\t\t\tconst preMiddleware = createMiddlewareImports(settings.middlewares.pre, 'pre');\n\t\t\t\t\tconst postMiddleware = createMiddlewareImports(settings.middlewares.post, 'post');\n\n\t\t\t\t\tconst code = `\n\t\t\t\t${\n\t\t\t\t\tuserMiddlewareIsPresent\n\t\t\t\t\t\t? `import { onRequest as userOnRequest } from '${resolvedMiddlewareId}';`\n\t\t\t\t\t\t: ''\n\t\t\t\t}\nimport { sequence } from 'astro:middleware';","sourceCodeStart":62,"sourceCodeEnd":98,"githubUrl":"https://github.com/withastro/astro/blob/52e6c34790cc8ac4e69e6135ace06049867e5c4a/packages/astro/src/core/middleware/vite-plugin.ts#L62-L98","documentation":"When no user middleware file exists, Astro's Vite middleware plugin serves a generated noop entry (NOOP_MIDDLEWARE). With i18n.routing set to 'manual', Astro refuses that noop: manual routing means Astro performs no locale routing for you, so a middleware file of your own is mandatory, and AstroErrorData.MissingMiddlewareForInternationalization is thrown from the plugin's load hook.","triggerScenarios":"Configuring i18n with routing: 'manual' (in Astro 5 this is the default once i18n is configured) while the project has no src/middleware.ts/js exporting onRequest; the middleware file was renamed, moved out of srcDir, or lost in a merge.","commonSituations":"Upgrading to Astro 5, where manual routing became the default and previously optional middleware became required; enabling i18n on an existing project that never had middleware; CI checkout where src/middleware.ts is not committed.","solutions":["Create src/middleware.ts that applies Astro's i18n middleware: export const onRequest = sequence(middleware({ redirectToDefaultLocale: true, prefixDefaultLocale: false })) using imports from 'astro:i18n' and 'astro:middleware'","Or write your own routing middleware exporting onRequest and implement the locale handling manually","Verify the file location and export: it must live at the srcDir root and export onRequest (or onPreparation)","If you did not intend manual routing, adjust the i18n config instead of keeping 'manual' without middleware"],"exampleFix":"// before: astro.config.mjs\nexport default defineConfig({ i18n: { defaultLocale: 'en', locales: ['en', 'fr'], routing: 'manual' } });\n// and no src/middleware.ts\n\n// after: create src/middleware.ts\nimport { sequence } from 'astro:middleware';\nimport { middleware } from 'astro:i18n';\n\nexport const onRequest = sequence(\n  middleware({\n    redirectToDefaultLocale: true,\n    prefixDefaultLocale: false,\n  })\n);","handlingStrategy":"validation","validationCode":"// run as a preflight/CI check in Node\nimport { existsSync } from 'node:fs';\nimport config from './astro.config.mjs';\n\nif (config.i18n?.routing === 'manual' && !existsSync('./src/middleware.ts')) {\n  throw new Error('i18n.routing \"manual\" requires src/middleware.ts exporting onRequest');\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Create src/middleware.ts in the same commit that enables i18n routing 'manual'","Keep the file at the srcDir root, named middleware.ts, exporting onRequest","Commit the middleware file — CI checkouts without it turn the config into a build error"],"tags":["i18n","routing","middleware","config","build-time"],"backgroundTag":"missing-required-middleware","analyzedSha":"52e6c34790cc8ac4e69e6135ace06049867e5c4a","analyzedAt":"2026-08-18T18:48:03.901Z","contentChangedAt":"2026-08-18T18:48:03.901Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}