sveltejs/kit · error · Error
`cache-control` header contains empty directives. ${error_su
Error message
`cache-control` header contains empty directives. ${error_suffix} What it means
SvelteKit validates cache-control headers set via setHeaders during prerendering. A directive like 'max-age=3600, , private' (empty string between commas) is malformed, so it throws with the offending value to surface the bug early.
Source
Thrown at packages/kit/src/runtime/server/validate-headers.js:29
'immutable',
'stale-while-revalidate',
'stale-if-error',
'no-transform',
'only-if-cached',
'max-stale',
'min-fresh'
]);
const CONTENT_TYPE_PATTERN =
/^(application|audio|example|font|haptics|image|message|model|multipart|text|video|x-[a-z]+)\/[-+.\w]+$/i;
/** @type {Record<string, (value: string) => void>} */
const HEADER_VALIDATORS = {
'cache-control': (value) => {
const error_suffix = `(While parsing "${value}".)`;
const parts = value.split(',').map((part) => part.trim());
if (parts.some((part) => !part)) {
throw new Error(`\`cache-control\` header contains empty directives. ${error_suffix}`);
}
const directives = parts.map((part) => part.split('=')[0].toLowerCase());
const invalid = directives.find((directive) => !VALID_CACHE_CONTROL_DIRECTIVES.has(directive));
if (invalid) {
throw new Error(
`Invalid cache-control directive "${invalid}". Did you mean one of: ${[...VALID_CACHE_CONTROL_DIRECTIVES].join(', ')}? ${error_suffix}`
);
}
},
'content-type': (value) => {
const type = value.split(';')[0].trim();
const error_suffix = `(While parsing "${value}".)`;
if (!CONTENT_TYPE_PATTERN.test(type)) {
throw new Error(`Invalid content-type value "${type}". ${error_suffix}`);
}
}View on GitHub (pinned to 03f1687fe6)
Solutions
- Remove the empty directive — check for trailing commas and empty interpolated variables
- Guard the value before setting: only include directives whose variables are truthy
- Validate the final string with a quick split(',') check in dev before shipping
Example fix
// before
event.setHeaders({ 'cache-control': `max-age=${ttl}, immutable` }); // ttl = ''
// after
event.setHeaders({ 'cache-control': ttl ? `max-age=${ttl}, immutable` : 'immutable' }); Defensive patterns
Strategy: validation
Validate before calling
function hasEmptyCacheDirectives(value) {
return value.split(',').some((p) => !p.trim());
}
// if (hasEmptyCacheDirectives(cc)) throw new Error('bad cache-control: ' + cc); Try / catch
try {
event.setHeaders({ 'cache-control': cc });
} catch (e) {
if (e.message.includes('empty directives')) console.error('Fix cache-control value:', cc);
} Prevention
- Filter out falsy interpolated values before building the header
- Join directives with .filter(Boolean).join(', ')
- Lint for hand-built cache-control template strings
When it happens
Trigger: setHeaders({ 'cache-control': 'public, , max-age=60' }) — a trailing comma like 'no-store,' or a manually-built string with empty segments.
Common situations: Template-string construction of cache-control where a variable is empty: `max-age=${ttl}, immutable` with ttl='' ; copy-pasted headers with stray commas.
Related errors
- Invalid cache-control directive "${invalid}". Did you mean o
- Invalid content-type value "${type}". ${error_suffix}
- Invalid value for environment variable ${env_prefix + name}:
- The ${protocol_header} header specified ${protocol} which is
- Could not determine host from the ${host_header ? `${host_he
AI-assisted analysis of sveltejs/kit@03f1687fe6 (2026-09-02).
Data as JSON: /api/errors/a979ab2aea0b7258.
Report an issue: GitHub.