withastro/astro · error · Error

SVG file does not contain an

Error message

SVG file does not contain an <svg> element

What it means

After optional optimization, Astro parses the SVG with ultrahtml and looks for a top-level `<svg>` element. If none is found it throws a plain Error ('SVG file does not contain an <svg> element') from packages/astro/src/assets/svg/utils.ts — the file parsed, but it is not actually an SVG document (no svg root element).

Solutions

  1. Open the file in a text editor and confirm it literally contains an `<svg>...</svg>` root element
  2. If it is an HTML or XML document, re-export the actual SVG from your design tool or source
  3. If an optimizer step strips the root, remove it from the pipeline or fix its output, then retry

Example fix

```html
<!-- before: hero.svg -->
<html><body><p>Not found</p></body></html>

<!-- after: hero.svg -->
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">…</svg>
```
Defensive patterns

Strategy: validation

Validate before calling

// verify an SVG document actually contains a root <svg> element
function hasSvgRoot(contents: string): boolean {
  return /<svg[\s>]/i.test(contents);
}

if (!hasSvgRoot(await readFile(path, 'utf8'))) {
  throw new Error(`${path} is not a valid SVG document`);
}

Type guard

function isSvgDocument(contents: string): boolean {
  return /<svg[\s>][\s\S]*<\/svg>\s*$/i.test(contents.trim());
}

Try / catch

try {
  await parseSvg({ path, contents });
} catch (err) {
  if (err instanceof Error && err.message.includes('does not contain an <svg> element')) {
    // skip this file or fail the build with a clearer, path-aware message
    throw new Error(`Invalid SVG asset: ${path}`);
  }
  throw err;
}

Prevention

When it happens

Trigger: An .svg file whose root is something else (an HTML page, a wrapper document, XML without an svg element); an empty or whitespace-only file with .svg extension; content that got mangled so the svg tag was stripped; an optimizer that returned non-SVG output.

Common situations: Saved a web page or received an XML error document and named it .svg; SVG generator emitted a wrapper with comments/doctype only; CI step that writes .svg files produced empty output; remote fetch saved an error body as .svg.

Related errors


AI-assisted analysis of withastro/astro@157c500c38 (2026-08-18). Data as JSON: /api/errors/610d7adffc00a047. Report an issue: GitHub.

Appendix: source

Thrown at packages/astro/src/assets/svg/utils.ts:36

	if (svgOptimizer) {
		try {
			processedContents = await svgOptimizer.optimize(contents, path);
		} 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 });

	// Collect text content of <style> elements for head propagation and CSP hashing
	const styles: string[] = [];
	for (const child of children) {
		if (child.type === ELEMENT_NODE && child.name === 'style') {
			const textContent = child.children
				?.filter((c: { type: number }) => c.type === TEXT_NODE)
				.map((c: { value: string }) => c.value)
				.join('');
			if (textContent) {
				styles.push(textContent);
			}
		}
	}

View on GitHub (pinned to 157c500c38)