{"record":{"id":"001c36fa82f8e2fe","repo":"withastro/astro","slug":"astro-cache-skipping-cache-for-url-pathname","errorCode":null,"errorMessage":"[astro:cache] Skipping cache for ${url.pathname}${url.search} because response includes Set-Cookie.","messagePattern":"\\[astro:cache\\] Skipping cache for (.+?)(.+?) because response includes Set-Cookie\\.","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"packages/astro/src/core/cache/memory-provider.ts","lineNumber":270,"sourceCode":"\tif (!entry.vary || !entry.varyValues) return true;\n\tfor (const header of entry.vary) {\n\t\tconst requestValue = request.headers.get(header) ?? '';\n\t\tif (requestValue !== entry.varyValues[header]) return false;\n\t}\n\treturn true;\n}\n\nfunction hasAtLeastOneCookie(cookies: AstroCookies | undefined): boolean {\n\treturn cookies ? !cookies.headers().next().done : false;\n}\n\nfunction hasSetCookieHeader(response: Response): boolean {\n\tif (response.headers.has('set-cookie')) return true;\n\treturn hasAtLeastOneCookie(getCookiesFromResponse(response));\n}\n\nfunction warnSkippedSetCookie(url: URL): void {\n\tconsole.warn(\n\t\t`[astro:cache] Skipping cache for ${url.pathname}${url.search} because response includes Set-Cookie.`,\n\t);\n}\n\n/**\n * Simple LRU cache backed by a Map (insertion-order iteration).\n * When the cache exceeds `max` entries, the oldest entry is evicted.\n */\nclass LRUMap<K, V> {\n\t#map = new Map<K, V>();\n\t#max: number;\n\n\tconstructor(max: number) {\n\t\tthis.#max = max;\n\t}\n\n\tget(key: K): V | undefined {\n\t\tconst value = this.#map.get(key);","sourceCodeStart":252,"sourceCodeEnd":288,"githubUrl":"https://github.com/withastro/astro/blob/3578d45d34226d63cff3d261c971c221de6794d2/packages/astro/src/core/cache/memory-provider.ts#L252-L288","documentation":"The built-in memory cache provider never stores a response that carries a Set-Cookie header, because replaying a cached Set-Cookie would leak one visitor's cookies to other visitors. When a response entering the cache sets a cookie, warnSkippedSetCookie() prints this warning and that response is simply not written to the cache.","triggerScenarios":"A route covered by `routeRules` caching (maxAge/swr) or by cache.set() calls whose final response includes Set-Cookie — set via Astro.cookies.set(), context.cookies.set(), or middleware attaching a cookie before the response is stored.","commonSituations":"Caching pages that also do A/B tests, theme switching, or consent-cookie assignment; login or locale-detection routes accidentally matched by a broad '/**' routeRules pattern.","solutions":["Narrow routeRules so cookie-setting routes are not covered (e.g. give /login or /set-theme maxAge: 0 or no rule)","Move cookie assignment into a non-cached endpoint or middleware outside the cached path","Accept the warning if per-user personalization is intentional — such responses are always cache misses by design"],"exampleFix":"// before — astro.config.mjs: cookie route matched by the broad cache rule\nexport default defineConfig({\n  cache: { provider: { entrypoint: 'astro/cache/memory' } },\n  routeRules: { '/**': { swr: 600 } }, // also caches /set-theme\n});\n\n// after — exclude the cookie-setting route\nexport default defineConfig({\n  cache: { provider: { entrypoint: 'astro/cache/memory' } },\n  routeRules: {\n    '/set-theme': { maxAge: 0 },\n    '/**': { swr: 600 },\n  },\n});","handlingStrategy":"validation","validationCode":"// when caching manually, only store cookie-free responses\nconst response = await next();\nconst cacheable = !response.headers.has('set-cookie');\nif (cacheable) {\n  // safe to cache\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep personalization (cookies) out of cached routes; assign cookies in dedicated endpoints","Review routeRules patterns whenever introducing cookies anywhere in the app","Treat Set-Cookie + cache as mutually exclusive by design; do not try to work around the skip"],"tags":["cache","cookies","set-cookie","memory-provider"],"backgroundTag":"uncacheable-response","analyzedSha":"3578d45d34226d63cff3d261c971c221de6794d2","analyzedAt":"2026-08-18T18:48:03.901Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}