denoland/deno · error · TypeError
Vary header must not contain '*'
Error message
Vary header must not contain '*'
What it means
Step 7 of Cache.put(): if the response has a Vary header whose comma-separated field list contains a trimmed '*', put() throws. A 'Vary: *' response can never be matched from cache, so storing it is pointless by definition.
Source
Thrown at ext/cache/01_cache.js:169
);
}
if (innerRequest.method !== "GET") {
throw new TypeError("Request method must be GET");
}
// Step 5.
const innerResponse = toInnerResponse(response);
// Step 6.
if (innerResponse.status === 206) {
throw new TypeError("Response status must not be 206");
}
// Step 7.
const varyHeader = getHeader(innerResponse.headerList, "vary");
if (varyHeader) {
const fieldValues = StringPrototypeSplit(varyHeader, ",");
for (let i = 0; i < fieldValues.length; ++i) {
const field = fieldValues[i];
if (StringPrototypeTrim(field) === "*") {
throw new TypeError("Vary header must not contain '*'");
}
}
}
// Step 8.
if (innerResponse.body !== null && innerResponse.body.unusable()) {
throw new TypeError("Response body is already used");
}
const stream = innerResponse.body?.stream;
let rid = null;
if (stream) {
const resourceBacking = getReadableStreamResourceBacking(
innerResponse.body?.stream,
);
if (resourceBacking) {
rid = resourceBacking.rid;
} else {View on GitHub (pinned to 89f33cbef2)
Solutions
- Skip caching when the vary header contains '*': check response.headers.get('vary')?.split(',').some((f) => f.trim() === '*').
- Server-side: stop sending 'Vary: *' for resources you want cached.
Example fix
// before
await cache.put(req, res); // res has Vary: *
// after
const vary = res.headers.get('vary') ?? '';
if (!vary.split(',').some((f) => f.trim() === '*')) {
await cache.put(req, res);
} Defensive patterns
Strategy: validation
Validate before calling
const vary = response.headers.get('vary') ?? '';
if (!vary.split(',').some((f) => f.trim() === '*')) {
await cache.put(request, response);
} Try / catch
try { await cache.put(req, res); } catch (e) { if (e instanceof TypeError) { /* uncacheable response: skip */ } else throw e; } Prevention
- Inspect the vary header before caching responses from servers you do not control.
- In tests, avoid mocking responses with 'Vary: *' unless you assert the cache rejects them.
When it happens
Trigger: The server sends 'Vary: *' (or a vary list containing '*') and the response is passed to cache.put().
Common situations: Servers or CDNs that emit 'Vary: *' to disable shared caching; personalized responses that client code still tries to cache.
Related errors
- Request url protocol must be 'http:' or 'https:': received '
- Request method must be GET
- BenchContext::end() has already been invoked
- Object is not a valid image or a path to an image. `Deno.jup
- Response status must not be 206
AI-assisted analysis of denoland/deno@89f33cbef2 (2026-08-16).
Data as JSON: /api/errors/4f4cbf1d9ac598d6.
Report an issue: GitHub.