withastro/astro · error · AstroError

IncorrectStrategyForI18n

IncorrectStrategyForI18n

Error message

The function `${functionName}` can only be used when the `i18n.routing.strategy` is set to `"manual"`.

What it means

Several exports of the astro:i18n virtual module — middleware, notFound, requestHasLocale, redirectToDefaultLocale, and redirectToFallback — exist only when you take full control of routing by setting i18n.routing to "manual" in astro.config. With any other routing configuration these functions are replaced with stubs that throw IncorrectStrategyForI18n, naming the function you called. This is intentional: with automatic routing Astro handles these concerns, so the manual APIs do not apply.

Solutions

  1. Set i18n: { routing: 'manual' } in astro.config.mjs if you truly want to drive routing yourself
  2. Otherwise remove the manual-only calls and let automatic routing plus fallback configuration handle it
  3. If you keep automatic routing but need custom logic, write a normal src/middleware.ts without the astro:i18n helpers

Example fix

// before — astro.config.mjs
export default defineConfig({
	i18n: { defaultLocale: 'en', locales: ['en', 'es'], routing: { prefixDefaultLocale: true } },
});

// after
export default defineConfig({
	i18n: { defaultLocale: 'en', locales: ['en', 'es'], routing: 'manual' },
});
Defensive patterns

Strategy: validation

Validate before calling

// astro.config.mjs — fail at config load instead of at request time
const config = defineConfig({
	i18n: { defaultLocale: 'en', locales: ['en', 'es'], routing: 'manual' },
});
// middleware(), notFound(), requestHasLocale(), redirectToDefaultLocale(),
// redirectToFallback() from 'astro:i18n' all require routing: 'manual'
if (config.i18n?.routing !== 'manual' && process.env.ASTRO_I18N_MANUAL_HELPERS) {
	throw new Error('astro:i18n manual helpers require i18n.routing: "manual"');
}

Type guard

const isManualI18nRouting = (routing: unknown): routing is 'manual' => routing === 'manual';

Prevention

When it happens

Trigger: Calling middleware(...) from astro:i18n in src/middleware.ts while i18n.routing is unset or set to an options object; calling redirectToDefaultLocale(context), notFound(context), requestHasLocale(context), or redirectToFallback(...) under non-manual routing.

Common situations: Copy-pasting the manual i18n middleware example from the docs without switching routing to 'manual'; migrating configs across Astro majors where routing options moved between string and object forms.

Related errors


AI-assisted analysis of withastro/astro@52e6c34790 (2026-08-18). Data as JSON: /api/errors/3e81f5514f7cdb8c. Report an issue: GitHub.

Appendix: source

Thrown at packages/astro/src/virtual-modules/i18n.ts:35

import type { MiddlewareHandler } from '../types/public/common.js';
import type { AstroConfig, ValidRedirectStatus } from '../types/public/config.js';
import type { APIContext } from '../types/public/context.js';
import type { ClientDeserializedManifest } from '../types/public/index.js';

const { trailingSlash, site, i18n, build } = config as ClientDeserializedManifest;
const { format } = build;
const isBuild = import.meta.env.PROD;
const { defaultLocale, locales, domains, fallback, routing } = i18n!;
const base = import.meta.env.BASE_URL;

let strategy = toRoutingStrategy(routing, domains);
let fallbackType = toFallbackType(routing);

export type GetLocaleOptions = I18nInternals.GetLocaleOptions;

const noop = (method: string) =>
	function () {
		throw new AstroError({
			...IncorrectStrategyForI18n,
			message: IncorrectStrategyForI18n.message(method),
		});
	};

/**
 * @param locale A locale
 * @param path An optional path to add after the `locale`.
 * @param options Customise the generated path
 *
 * Returns a _relative_ path with passed locale.
 *
 * ## Errors
 *
 * Throws an error if the locale doesn't exist in the list of locales defined in the configuration.
 *
 * ## Examples
 *

View on GitHub (pinned to 52e6c34790)