{"record":{"id":"4433ccd94ead7e99","repo":"withastro/astro","slug":"sessionstoragesaveerror","errorCode":"SessionStorageSaveError","errorMessage":"The session key was not provided.","messagePattern":"The session key was not provided\\.","errorType":"exception","errorClass":"AstroError","httpStatus":null,"severity":"error","filePath":"packages/astro/src/core/session/runtime.ts","lineNumber":186,"sourceCode":"\t\t}\n\t\tthis.#dirty = true;\n\t}\n\n\t/**\n\t * Sets a session value. The session is created if it does not exist.\n\t */\n\n\tset<T = void, K extends string = keyof App.SessionData | (string & {})>(\n\t\tkey: K,\n\t\tvalue: T extends void\n\t\t\t? K extends keyof App.SessionData\n\t\t\t\t? App.SessionData[K]\n\t\t\t\t: any\n\t\t\t: NoInfer<T>,\n\t\t{ ttl }: { ttl?: number } = {},\n\t) {\n\t\tif (!key) {\n\t\t\tthrow new AstroError({\n\t\t\t\t...SessionStorageSaveError,\n\t\t\t\tmessage: 'The session key was not provided.',\n\t\t\t});\n\t\t}\n\t\t// save a clone of the passed in object so later updates are not\n\t\t// persisted into the store. Attempting to serialize also allows\n\t\t// us to throw an error early if needed.\n\t\tlet cloned: T;\n\t\ttry {\n\t\t\tcloned = unflatten(JSON.parse(stringify(value)));\n\t\t} catch (err) {\n\t\t\tthrow new AstroError(\n\t\t\t\t{\n\t\t\t\t\t...SessionStorageSaveError,\n\t\t\t\t\tmessage: `The session data for ${key} could not be serialized.`,\n\t\t\t\t\thint: 'See the devalue library for all supported types: https://github.com/rich-harris/devalue',\n\t\t\t\t},\n\t\t\t\t{ cause: err },","sourceCodeStart":168,"sourceCodeEnd":204,"githubUrl":"https://github.com/withastro/astro/blob/3578d45d34226d63cff3d261c971c221de6794d2/packages/astro/src/core/session/runtime.ts#L168-L204","documentation":"AstroSession.set() requires a non-empty string key under which the value is stored in the session map (and later serialized). The method throws SessionStorageSaveError with 'The session key was not provided.' when the key argument is falsy — empty string, undefined, or null. Storing under a falsy key would silently create unreachable data, so it is rejected immediately.","triggerScenarios":"Astro.session.set('', cart); Astro.session.set(undefined, data) (often from a typo'd variable or an optional variable at runtime); passing a computed key that evaluates to '' when its source field is missing, e.g. session.set(user.id, role) where user.id is undefined.","commonSituations":"Dynamic keys derived from request data (user id, locale code) that can be empty; destructuring with a renamed variable so the intended key variable is undefined; TS code bypassed with any where the key is genuinely missing.","solutions":["Pass a concrete non-empty string key: Astro.session.set('cart', cart).","If the key is computed, default or validate it first: const key = user?.id; if (!key) return;","Check for typos between the key variable name used in set() and the one you defined."],"exampleFix":"// before\nAstro.session.set(userId, { role }); // userId is undefined for anonymous visitors\n\n// after\nif (userId) {\n  Astro.session.set(`user:${userId}`, { role });\n}","handlingStrategy":"type-guard","validationCode":"const key = computedKey ?? '';\nif (key.length === 0) {\n  throw new TypeError('session key required');\n}\nAstro.session.set(key, value);","typeGuard":"function isNonEmptySessionKey(key: unknown): key is string {\n  return typeof key === 'string' && key.length > 0;\n}","tryCatchPattern":null,"preventionTips":["Never pass computed keys without a guard; optional ids are undefined for someone.","Namespace keys with a prefix: `user:${id}`, `cart:${cartId}`.","Let TypeScript's string literal keys (App.SessionData) surface typos at compile time."],"tags":["astro","sessions","validation","runtime"],"backgroundTag":"missing-session-key","analyzedSha":"3578d45d34226d63cff3d261c971c221de6794d2","analyzedAt":"2026-08-18T18:48:03.901Z","contentChangedAt":"2026-08-18T18:48:03.901Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}