withastro/astro · error · Error

Integration ${integrationName} is injecting a type that does

Error message

Integration ${integrationName} is injecting a type that does not end with ".d.ts"

What it means

`normalizeInjectedTypeFilename` requires every type file an integration injects via `updateConfig({ types... })` to end in `.d.ts` so Astro can place it correctly under the integration's codegen directory. Filenames not ending in `.d.ts` are rejected with a plain Error (no AstroError code).

Source

Thrown at packages/astro/src/integrations/hooks.ts:161

		 * @param appId - The id of the app that was toggled
		 * @param callback - The callback to run when the app is toggled
		 */
		onAppToggled: (appId: string, callback: (data: { state: boolean }) => void) => {
			server.hot.on(`${serverEventPrefix}:${appId}:toggled`, callback);
		},
	};
}

// Will match any invalid characters (will be converted to _). We only allow a-zA-Z0-9.-_
const SAFE_CHARS_RE = /[^\w.-]/g;

export function normalizeCodegenDir(integrationName: string): string {
	return `./integrations/${integrationName.replace(SAFE_CHARS_RE, '_')}/`;
}

export function normalizeInjectedTypeFilename(filename: string, integrationName: string): string {
	if (!filename.endsWith('.d.ts')) {
		throw new Error(
			`Integration ${colors.bold(integrationName)} is injecting a type that does not end with "${colors.bold('.d.ts')}"`,
		);
	}
	return `${normalizeCodegenDir(integrationName)}${filename.replace(SAFE_CHARS_RE, '_')}`;
}

interface RunHookConfigSetup {
	settings: AstroSettings;
	command: 'dev' | 'build' | 'preview' | 'sync';
	logger: AstroLogger;
	isRestart?: boolean;
	fs?: typeof fsMod;
}

export async function runHookConfigSetup({
	settings,
	command,
	logger,

View on GitHub (pinned to d081033d5f)

Solutions

  1. Rename the injected type file so it ends with `.d.ts` (e.g. `'my-types.d.ts'`).
  2. Confirm the filename passed to the injection API is exactly what you intend — no extra suffix or extension.
  3. Update the integration to follow the `.d.ts` requirement documented for type injection.

Example fix

// before
updateConfig({ types: [{ filename: 'types.ts', content: decl, declaration: true }] })

// after
updateConfig({ types: [{ filename: 'types.d.ts', content: decl, declaration: true }] })
Defensive patterns

Strategy: validation

Validate before calling

function assertDtsFilename(filename) {
  if (!filename.endsWith('.d.ts')) {
    throw new Error(`Type filename must end with .d.ts: ${filename}`);
  }
}

Type guard

function isDtsFilename(filename) {
  return typeof filename === 'string' && filename.endsWith('.d.ts');
}

Try / catch

null

Prevention

When it happens

Trigger: An integration's `astro:config:setup` (or equivalent) hook calls the type-injection path with a filename like `'types.ts'`, `'router.d.mts'`, or `'astro-env.d'` — anything whose suffix isn't exactly `.d.ts`.

Common situations: Authoring a custom integration and passing a normal `.ts` filename by mistake; renaming a type file but forgetting the `.d.ts` convention; an integration built against an older API that accepted other extensions.

Related errors


AI-assisted analysis of withastro/astro@d081033d5f (2026-08-12). Data as JSON: /api/errors/3d4577338c254732. Report an issue: GitHub.