withastro/astro · warning
A resource was added to `${specific}`, but `${general}` also
Error message
A resource was added to `${specific}`, but `${general}` also defines custom resources (${defaultResources.join(' ')}). Because `${specific}` overrides `${general}` for its scope (browsers do not fall back), those resources will not apply there. Add them to `${specific}` as well if needed. What it means
In Content-Security-Policy, specific directives (script-src-elem/-attr, style-src-elem/-attr) fully replace the general directive (script-src/style-src) for their scope — browsers do not merge or fall back. When a resource is added to a specific directive while the general one also lists custom default resources, Astro warns (deduped once per family+kind per request via the warnedFallback set) that the general resources will not apply in that scope.
Source
Thrown at packages/astro/src/core/fetch/fetch-state.ts:696
family === 'script' ? state.result.scriptDirective : state.result.styleDirective;
// Astro's element hashes are folded into the `-elem` directive automatically, so the
// footgun is specifically user-provided `default`-kind resources on the general directive,
// which do NOT carry over to the more specific directive.
const defaultResources = directive.resources
.map(normalizeCspResourceEntry)
.filter((entry) => entry.kind === 'default')
.map((entry) => entry.resource);
if (defaultResources.length === 0) {
return;
}
const key = `${family}:${kind}`;
if (warnedFallback.has(key)) {
return;
}
warnedFallback.add(key);
const general = `${family}-src`;
const specific = `${general}-${kind === 'element' ? 'elem' : 'attr'}`;
state.logger.warn(
'csp',
`A resource was added to \`${specific}\`, but \`${general}\` also defines custom resources (${defaultResources.join(
' ',
)}). Because \`${specific}\` overrides \`${general}\` for its scope (browsers do not fall back), those resources will not apply there. Add them to \`${specific}\` as well if needed.`,
);
};
return {
insertDirective(payload) {
if (state.result) {
state.result.directives = pushDirective(state.result.directives, payload);
}
},
insertScriptResource(payload) {
if (!state.result) return;
warnFallback('script', normalizeCspResourceEntry(payload).kind);
state.result.scriptDirective.resources.push(payload);
},
insertStyleResource(payload) {View on GitHub (pinned to e294953aa8)
Solutions
- Add the general directive's resources to the specific directive as well (repeat them for the elem/attr kinds)
- Or drop the custom defaults from the general directive so only the specific one carries resources
- Inspect the rendered Content-Security-Policy header to confirm the effective policy after the change
Example fix
// before — defaults on script-src get shadowed by script-src-elem additions
security: {
csp: {
scriptDirective: {
resources: [
{ value: "'self'" }, // kind 'default'
{ value: 'https://cdn.example.com', kind: 'elem' },
],
},
},
}
// after — repeat the defaults for the elem scope
security: {
csp: {
scriptDirective: {
resources: [
{ value: "'self'" },
{ value: "'self'", kind: 'elem' },
{ value: 'https://cdn.example.com', kind: 'elem' },
],
},
},
} Defensive patterns
Strategy: validation
Validate before calling
// mirror the browser's no-fallback rule before shipping CSP config
function checkCspShadowing(cfg) {
for (const [dir, family] of [[cfg.scriptDirective, 'script'], [cfg.styleDirective, 'style']]) {
const defaults = dir?.resources?.filter((r) => r.kind === undefined || r.kind === 'default') ?? [];
const specifics = dir?.resources?.filter((r) => r.kind === 'elem' || r.kind === 'attr') ?? [];
if (defaults.length && specifics.length) {
console.warn(`${family}-src resources (${defaults.map((r) => r.value).join(' ')}) are shadowed by ${family}-src-elem/-attr`);
}
}
} Prevention
- Pick one directive level per family: either the general directive or the elem/attr ones, not both
- When both levels exist, repeat the general resources on the specific directive
- Validate the final Content-Security-Policy header with a CSP evaluator in your test suite
When it happens
Trigger: security.csp configures custom resources on the general script-src/style-src directive (kind 'default'), and route code or config also adds resources with kind 'elem' or 'attr' — the specific directive then overrides the general one with no fallback.
Common situations: Mixing directive levels when allowing third-party scripts; configs that grew defaults first and per-element/per-attribute additions later; migrating policies copied from other frameworks.
Related errors
- `security.csp.${name}Directive` defines `${name}-src` resour
- Shiki syntax highlighting uses inline styles that are not co
- context.csp was used when rendering the route ${colors.green
- RemoteImageNotAllowed
- Invalid URL encoding
AI-assisted analysis of withastro/astro@e294953aa8 (2026-08-18).
Data as JSON: /api/errors/c87b89a54e677b80.
Report an issue: GitHub.