{"record":{"id":"9891a41dde6ab0b1","repo":"withastro/astro","slug":"localsnotanobject","errorCode":"LocalsNotAnObject","errorMessage":"`locals` can only be assigned to an object. Other values like numbers, strings, etc. are not accepted.","messagePattern":"`locals` can only be assigned to an object\\. Other values like numbers, strings, etc\\. are not accepted\\.","errorType":"validation","errorClass":"AstroError","httpStatus":null,"severity":"error","filePath":"packages/astro/src/core/middleware/index.ts","lineNumber":114,"sourceCode":"\t\tget preferredLocaleList(): string[] | undefined {\n\t\t\treturn (preferredLocaleList ??= computePreferredLocaleList(request, userDefinedLocales));\n\t\t},\n\t\tget currentLocale(): string | undefined {\n\t\t\treturn (currentLocale ??= computeCurrentLocale(route, userDefinedLocales, defaultLocale));\n\t\t},\n\t\turl,\n\t\tget originPathname() {\n\t\t\treturn getOriginPathname(request);\n\t\t},\n\t\tget clientAddress() {\n\t\t\tif (clientAddress) {\n\t\t\t\treturn clientAddress;\n\t\t\t}\n\t\t\tthrow new AstroError(AstroErrorData.StaticClientAddressNotAvailable);\n\t\t},\n\t\tget locals() {\n\t\t\tif (typeof locals !== 'object') {\n\t\t\t\tthrow new AstroError(AstroErrorData.LocalsNotAnObject);\n\t\t\t}\n\t\t\treturn locals;\n\t\t},\n\t\tset locals(_) {\n\t\t\tthrow new AstroError(AstroErrorData.LocalsReassigned);\n\t\t},\n\t\tsession: undefined,\n\t\tcache: new DisabledAstroCache(),\n\t\tcsp: undefined,\n\t\tlogger: {\n\t\t\tinfo() {},\n\t\t\twarn() {},\n\t\t\terror() {},\n\t\t},\n\t};\n\treturn Object.assign(context, {\n\t\tgetActionResult: createGetActionResult(context.locals),\n\t\tcallAction: createCallAction(context),","sourceCodeStart":96,"sourceCodeEnd":132,"githubUrl":"https://github.com/withastro/astro/blob/d081033d5fe8e8a68c4bbbad4af9d2deb9c74bca/packages/astro/src/core/middleware/index.ts#L96-L132","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nconst ctx = createContext({ request, locals: null });\n\n// after\nconst ctx = createContext({ request, locals: {} });","handlingStrategy":"validation","validationCode":"// Ensure locals is an object before reading it.\nif (typeof locals !== 'object' || locals === null) {\n  locals = {}; // initialize\n}\nconst ctx = createContext({ request, locals });","typeGuard":"function isLocalsObject(locals: unknown): locals is Record<string, unknown> {\n  return typeof locals === 'object' && locals !== null;\n}","tryCatchPattern":"try {\n  ctx.locals;\n} catch (e) {\n  if (e instanceof Error && /assigned to an object/i.test(e.message)) {\n    locals = {}; // initialize and retry\n  } else throw e;\n}","preventionTips":["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."],"tags":["locals","middleware","context","state"],"backgroundTag":null,"analyzedSha":"d081033d5fe8e8a68c4bbbad4af9d2deb9c74bca","analyzedAt":"2026-08-12T13:37:29.035Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}