withastro/astro · error · AstroError
LocalsNotAnObject
LocalsNotAnObject
Error message
`locals` can only be assigned to an object. Other values like numbers, strings, etc. are not accepted.
What it means
Thrown by the locals getter on the APIContext from createContext when the locals variable is not an object type. Astro.locals must be an object so properties can be attached; if it was somehow set to a primitive (string, number, null), the getter refuses to return it.
Source
Thrown at packages/astro/src/core/middleware/index.ts:114
get preferredLocaleList(): string[] | undefined {
return (preferredLocaleList ??= computePreferredLocaleList(request, userDefinedLocales));
},
get currentLocale(): string | undefined {
return (currentLocale ??= computeCurrentLocale(route, userDefinedLocales, defaultLocale));
},
url,
get originPathname() {
return getOriginPathname(request);
},
get clientAddress() {
if (clientAddress) {
return clientAddress;
}
throw new AstroError(AstroErrorData.StaticClientAddressNotAvailable);
},
get locals() {
if (typeof locals !== 'object') {
throw new AstroError(AstroErrorData.LocalsNotAnObject);
}
return locals;
},
set locals(_) {
throw new AstroError(AstroErrorData.LocalsReassigned);
},
session: undefined,
cache: new DisabledAstroCache(),
csp: undefined,
logger: {
info() {},
warn() {},
error() {},
},
};
return Object.assign(context, {
getActionResult: createGetActionResult(context.locals),
callAction: createCallAction(context),View on GitHub (pinned to d081033d5f)
Solutions
- Ensure locals is initialized to an object ({} ) by the adapter/integration that creates the context.
- In tests, set locals to a plain object, not null or a primitive.
- If you control context creation, always pass locals: {} as the default.
Example fix
// before
const ctx = createContext({ request, locals: null });
// after
const ctx = createContext({ request, locals: {} }); Defensive patterns
Strategy: validation
Validate before calling
// Ensure locals is an object before reading it.
if (typeof locals !== 'object' || locals === null) {
locals = {}; // initialize
}
const ctx = createContext({ request, locals }); Type guard
function isLocalsObject(locals: unknown): locals is Record<string, unknown> {
return typeof locals === 'object' && locals !== null;
} Try / catch
try {
ctx.locals;
} catch (e) {
if (e instanceof Error && /assigned to an object/i.test(e.message)) {
locals = {}; // initialize and retry
} else throw e;
} Prevention
- Always initialize locals to {} when creating contexts.
- In tests, pass locals as a plain object, never null.
- Adapters should default locals to {} before calling createContext.
When it happens
Trigger: Reading context.locals when the underlying locals value is not typeof 'object' (e.g. it was replaced with a primitive somewhere, or initialization left it as null/undefined). The check `typeof locals !== 'object'` in the getter throws LocalsNotAnObject.
Common situations: An adapter or integration that initializes locals to a non-object; tests that stub context with locals as null; edge cases where locals was never initialized to an empty object.
Related errors
- LocalsReassigned
- LocalsReassigned
- StaticClientAddressNotAvailable
- The passed value can't be serialized.
- MiddlewareNotAResponse
AI-assisted analysis of withastro/astro@d081033d5f (2026-08-12).
Data as JSON: /api/errors/9891a41dde6ab0b1.
Report an issue: GitHub.