{"record":{"id":"e1175389732c83e6","repo":"withastro/astro","slug":"integration-colors-bold-integrationname-is-inj","errorCode":null,"errorMessage":"Integration ${colors.bold(integrationName)} is injecting a type that does not end with \"${colors.bold('.d.ts')}\"","messagePattern":"Integration (.+?) is injecting a type that does not end with \"(.+?)\"","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/astro/src/integrations/hooks.ts","lineNumber":161,"sourceCode":"\t\t * @param appId - The id of the app that was toggled\n\t\t * @param callback - The callback to run when the app is toggled\n\t\t */\n\t\tonAppToggled: (appId: string, callback: (data: { state: boolean }) => void) => {\n\t\t\tserver.hot.on(`${serverEventPrefix}:${appId}:toggled`, callback);\n\t\t},\n\t};\n}\n\n// Will match any invalid characters (will be converted to _). We only allow a-zA-Z0-9.-_\nconst SAFE_CHARS_RE = /[^\\w.-]/g;\n\nexport function normalizeCodegenDir(integrationName: string): string {\n\treturn `./integrations/${integrationName.replace(SAFE_CHARS_RE, '_')}/`;\n}\n\nexport function normalizeInjectedTypeFilename(filename: string, integrationName: string): string {\n\tif (!filename.endsWith('.d.ts')) {\n\t\tthrow new Error(\n\t\t\t`Integration ${colors.bold(integrationName)} is injecting a type that does not end with \"${colors.bold('.d.ts')}\"`,\n\t\t);\n\t}\n\treturn `${normalizeCodegenDir(integrationName)}${filename.replace(SAFE_CHARS_RE, '_')}`;\n}\n\ninterface RunHookConfigSetup {\n\tsettings: AstroSettings;\n\tcommand: 'dev' | 'build' | 'preview' | 'sync';\n\tlogger: AstroLogger;\n\tisRestart?: boolean;\n\tfs?: typeof fsMod;\n}\n\nexport async function runHookConfigSetup({\n\tsettings,\n\tcommand,\n\tlogger,","sourceCodeStart":143,"sourceCodeEnd":179,"githubUrl":"https://github.com/withastro/astro/blob/52e6c34790cc8ac4e69e6135ace06049867e5c4a/packages/astro/src/integrations/hooks.ts#L143-L179","documentation":"Integrations can inject TypeScript declaration files via `injectType({ filename })`. Astro normalizes each injected filename into the codegen directory, but requires it to be a declaration file: normalizeInjectedTypeFilename() throws this plain Error when the filename does not end with `.d.ts`. It is a contract violation by the integration, surfaced at config setup time.","triggerScenarios":"An integration's `astro:config:setup` hook calling injectType({ filename: 'types.ts' }) or 'index.d'; filenames built dynamically (e.g. name + '.d') that lose the extension; porting an integration from an older API that accepted arbitrary filenames.","commonSituations":"Authoring or maintaining a community integration; a typo in the extension; code generating the filename from a variable that already contains an extension.","solutions":["Pass a filename ending in `.d.ts`: injectType({ filename: 'my-integration.d.ts' }).","If the name is dynamic, append the extension after sanitizing: `${name}.d.ts`.","If the error comes from a third-party integration, update it or file an issue - the call site is in the integration, not your app."],"exampleFix":"// before - inside an integration's astro:config:setup\nupdateConfig({ injectType: { filename: 'my-types.ts' } });\n\n// after\nupdateConfig({ injectType: { filename: 'my-types.d.ts' } });","handlingStrategy":"validation","validationCode":"// inside an integration, before injectType\nfunction injectedTypeFilename(name: string): string {\n  const filename = name.endsWith('.d.ts') ? name : name + '.d.ts';\n  if (!filename.endsWith('.d.ts')) throw new Error('type filename must end with .d.ts');\n  return filename;\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always append '.d.ts' when constructing injected type filenames dynamically.","Cover injectType calls with a unit test that runs the setup hook against a stub config.","Type hook parameters with the exported HookParameters types so contract drift is visible."],"tags":["integrations","typescript","plugin-api"],"backgroundTag":"invalid-integration-contract","analyzedSha":"52e6c34790cc8ac4e69e6135ace06049867e5c4a","analyzedAt":"2026-08-18T18:48:03.901Z","contentChangedAt":"2026-08-18T18:48:03.901Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}