withastro/astro · error · AstroError
CannotOptimizeSvg
CannotOptimizeSvg
Error message
An error occurred while optimizing SVG file "${path}" with the "${svgOptimizer.name}" optimizer. What it means
Astro throws this when a configured SVG optimizer's optimize() function rejects while processing an imported SVG asset. The SVG pipeline (experimental.svgOptimizer, e.g. svgo) is invoked on the file contents before parsing, and any rejection from its optimize() is wrapped as an AstroError carrying the original error as cause. The message names the file path and the optimizer's `name` field so you can tell which optimizer failed.
Source
Thrown at packages/astro/src/assets/svg/utils.ts:22
import { dropAttributes } from '../runtime.js';
import type { ImageMetadata } from '../types.js';
import type { SvgOptimizer } from './types.js';
async function parseSvg({
path,
contents,
svgOptimizer,
}: {
path: string;
contents: string;
svgOptimizer: SvgOptimizer | undefined;
}) {
let processedContents = contents;
if (svgOptimizer) {
try {
processedContents = await svgOptimizer.optimize(contents);
} catch (cause) {
throw new AstroError(
{
...AstroErrorData.CannotOptimizeSvg,
message: AstroErrorData.CannotOptimizeSvg.message(path, svgOptimizer.name),
},
{ cause },
);
}
}
const root = parse(processedContents);
const svgNode = root.children.find(
({ name, type }: { name: string; type: number }) => type === ELEMENT_NODE && name === 'svg',
);
if (!svgNode) {
throw new Error('SVG file does not contain an <svg> element');
}
const { attributes, children } = svgNode;
const body = renderSync({ ...root, children });
View on GitHub (pinned to d081033d5f)
Solutions
- Inspect the `cause` on the AstroError in your stack trace — it carries the optimizer's original error and is the real reason.
- Run the same SVG through the optimizer directly (e.g. `svgo input.svg`) outside Astro to reproduce and isolate the bad input.
- Fix or re-export the offending SVG from your editor (remove unsupported elements/attributes the optimizer flagged).
- If the optimizer config is wrong, correct experimental.svgOptimizer in astro.config.mjs (or the options you pass to svgoOptimizer()).
- Temporarily unset experimental.svgOptimizer to confirm the SVG itself is otherwise valid, then reintroduce the optimizer.
Example fix
// before
import svgo from './broken.svg'; // optimizer throws on this file
// after — sanitize the SVG, or pass tolerant svgo config
import { svgoOptimizer } from 'astro/assets/svg/svgo';
export default defineConfig({
experimental: { svgOptimizer: svgoOptimizer({ floatPrecision: 1, multipass: true }) },
}); Defensive patterns
Strategy: try-catch
Validate before calling
// Validate SVG is well-formed and has an <svg> root before importing through the optimizer
import { readFileSync } from 'node:fs';
function looksLikeSvg(path: string) {
const txt = readFileSync(path, 'utf8');
return /<svg[\s>]/i.test(txt) && txt.trim().endsWith('</svg>');
}
// skip optimizer when false Type guard
import type { SvgOptimizer } from 'astro/assets';
function isSvgOptimizer(v: unknown): v is SvgOptimizer {
return typeof v === 'object' && v !== null
&& typeof (v as SvgOptimizer).name === 'string'
&& typeof (v as SvgOptimizer).optimize === 'function';
} Try / catch
try {
// import/optimization happens inside Astro's pipeline; catch at the build boundary
await astroBuild();
} catch (e) {
if (e instanceof Error && /CannotOptimizeSvg/.test(e.message)) {
console.error('SVG optimizer failed for', e.message, '\ncause:', e.cause);
} else throw e;
} Prevention
- Run new SVGs through your optimizer standalone before committing them.
- Pin your svgo/optimizer version and lock its config.
- Keep experimental.svgOptimizer disabled in CI unless you intentionally test optimization.
When it happens
Trigger: Calling ESM-import of an .svg asset while experimental.svgOptimizer is set, where the optimizer's optimize(contents) throws (invalid SVG syntax, unsupported node, bad optimizer config, or a transformer bug). Triggered via assets pipeline -> svg/utils.ts optimizeSvg() when svgOptimizer is defined.
Common situations: Pointing experimental.svgOptimizer at svgo with a custom pluginConfig that chokes on a particular SVG; an SVG containing elements/attributes the optimizer cannot handle; an author-supplied custom SvgOptimizer whose optimize() throws on edge inputs; version mismatch between svgo and a hand-written plugin.
Related errors
- SVG file does not contain an <svg> element
- RemoteImageNotAllowed
- Unsupported image format "${options.format}"
- UnsupportedImageConversion
- UnsupportedImageFormat
AI-assisted analysis of withastro/astro@d081033d5f (2026-08-12).
Data as JSON: /api/errors/6645f87dff0c9726.
Report an issue: GitHub.