withastro/astro · error · AstroError
LocalsReassigned
LocalsReassigned
Error message
`locals` cannot be assigned directly.
What it means
On the fetch-state-backed Astro global, `locals` is getter-only; the setter throws AstroErrorData.LocalsReassigned. The locals object keeps one stable identity for the whole request so middleware, pages, and actions can decorate the same object — replacing the instance would orphan every reference already handed out. Mutating properties is always allowed.
Solutions
- Assign properties instead of the object: Astro.locals.user = user
- To merge many fields at once, use Object.assign(Astro.locals, values)
- Initialize locals fields once in middleware (context.locals.isLogged = ...) so pages never need to reassign
- To remove data, delete the key: delete Astro.locals.temp
Example fix
// before
Astro.locals = { user: session.user };
// after
Astro.locals.user = session.user; Defensive patterns
Strategy: validation
Validate before calling
function setLocals(values: Partial<App.Locals>): void {
Object.assign(Astro.locals, values);
}
// use setLocals({ user }) instead of Astro.locals = { user } Prevention
- Initialize locals fields in middleware (context.locals.x = ...) once per request
- Only mutate properties; never assign the container
- Grep for 'locals =' (with the assignment operator) during code review
When it happens
Trigger: `Astro.locals = {...}` anywhere in .astro frontmatter, middleware, endpoints, or actions; attempting to 'reset' locals by assigning a fresh object; spread-style replacement like Astro.locals = { ...Astro.locals, user }.
Common situations: Developers used to frameworks where ctx.state is assignable; refactors that move locals initialization from middleware into a page; trying to clear stale keys between requests in dev and writing an assignment.
Related errors
- AstroResponseHeadersReassigned
- LocalsReassigned
- LocalsNotAnObject
- ResponseSentError
- The passed value can't be serialized.
AI-assisted analysis of withastro/astro@e294953aa8 (2026-08-18).
Data as JSON: /api/errors/5847eadb40289381.
Report an issue: GitHub.
Appendix: source
Thrown at packages/astro/src/core/fetch/fetch-state.ts:1176
const ctx = {
get cookies() {
return state.cookies;
},
routePattern: this.routeData!.route,
isPrerendered: this.routeData!.prerender,
get clientAddress() {
return state.getClientAddress();
},
get currentLocale() {
return state.computeCurrentLocale();
},
generator: ASTRO_GENERATOR,
get locals() {
return state.locals;
},
set locals(_) {
throw new AstroError(AstroErrorData.LocalsReassigned);
},
// SAFETY: getActionAPIContext is only called after route resolution,
// so routeData is always set and the params getter always returns a value.
params: this.params!,
get preferredLocale() {
return state.computePreferredLocale();
},
get preferredLocaleList() {
return state.computePreferredLocaleList();
},
request: this.request,
site: getSite(this.manifest),
url: this.url,
get originPathname() {
return getOriginPathname(state.request);
},
get csp() {
return state.getCsp();View on GitHub (pinned to e294953aa8)