withastro/astro · error · Error
<script src="${src}"> references an asset in the "${public
Error message
<script src="${src}"> references an asset in the "${publicDir}" directory. Please add the "is:inline" directive to keep this asset from being bundled.
File: ${id} What it means
Thrown by the Astro Vite plugin when a `<script src="/...">` in a `.astro` component points at a file inside the configured `publicDir` (default `public/`). Astro tries to bundle external script references, but files in `public/` are served as-is and must not be processed by the bundler. The fix is to mark the script `is:inline` so Astro leaves it untouched.
Source
Thrown at packages/astro/src/vite-plugin-astro/index.ts:213
// SSR script only exists to make them appear in the module graph.
if (isAstroServerEnvironment(this.environment)) {
return {
code: `/* client script, empty in SSR: ${id} */`,
moduleType: 'ts',
};
}
const script = compileMetadata.scripts[query.index];
if (!script) {
throw new Error(`No script at index ${query.index}`);
}
if (script.type === 'external') {
const src = script.src!;
if (src.startsWith('/') && !isBrowserPath(src)) {
const publicDir =
config.publicDir.pathname.replace(/\/$/, '').split('/').pop() + '/';
throw new Error(
`\n\n<script src="${src}"> references an asset in the "${publicDir}" directory. Please add the "is:inline" directive to keep this asset from being bundled.\n\nFile: ${id}`,
);
}
}
const result: vite.Rolldown.SourceDescription = {
code: '',
moduleType: 'ts',
meta: {
vite: {
lang: 'ts',
},
},
};
switch (script.type) {
case 'inline': {
result.code = script.code ?? '';View on GitHub (pinned to d081033d5f)
Solutions
- Add `is:inline` to the script tag: `<script is:inline src="/lib/analytics.js">`.
- Alternatively, move the file out of `public/` into `src/` and import it as a module so Astro can bundle it.
- If the script is a remote URL (https://), it is not affected — only absolute local paths starting with `/` are checked.
Example fix
<!-- before --> <script src="/lib/analytics.js"></script> <!-- after --> <script is:inline src="/lib/analytics.js"></script>
Defensive patterns
Strategy: validation
Validate before calling
// In your .astro file, before referencing a public asset script:
const isPublicAsset = (src) => src.startsWith('/') && !src.startsWith('//');
// If true, always render with is:inline. Prevention
- Always add is:inline to scripts that reference /public assets.
- Keep third-party vendor scripts in public/ and reference them with is:inline.
- For bundleable scripts, place them under src/ and import them instead of using src=.
When it happens
Trigger: Writing `<script src="/lib/analytics.js">` where `public/lib/analytics.js` exists. The plugin detects `src.startsWith('/') && !isBrowserPath(src)` and derives the publicDir name from `config.publicDir`. Any absolute `/...` script whose target lives under public triggers it.
Common situations: Adding a third-party script (analytics, widgets) by dropping the file into `public/` and referencing it from a layout. Migrating from plain HTML where `<script src>` worked without bundler awareness. Forgetting `is:inline` on scripts that should bypass Vite.
Related errors
- Astro components cannot be used in the browser. Tried to ren
- Unable to render ${result.pathname} because it contains an u
- FontFamilyNotFound
- ImageMissingAlt
- ImageMissingAlt
AI-assisted analysis of withastro/astro@d081033d5f (2026-08-12).
Data as JSON: /api/errors/442b9f72acee55a7.
Report an issue: GitHub.