Symptom
Rasterising an SVG icon with ImageMagick produces the background but none of the linework. Exit code 0, no warning on stderr, valid PNG written. The failure is only visible if you actually look at the image, which is exactly what a scripted build does not do.
Concretely, this SVG:
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">
<rect width="64" height="64" rx="13" fill="#3b6e4a"/>
<g fill="none" stroke="#fafaf7" stroke-width="7.5" stroke-linecap="round">
<path d="M32 57V23"/>
<path d="M32 40 15 25"/>
<path d="M32 40 49 25"/>
</g>
</svg>renders as a bare green rounded square. All three paths vanish.
It is not <g> attribute inheritance: moving stroke, stroke-width and stroke-linecap onto each <path> individually changes nothing. It is not the -resize step either; the paths are already gone at parse time.
Cause
ImageMagick delegates SVG to librsvg when it is compiled in. When it is not, it falls back to MSVG, its own minimal XML-based renderer. MSVG handles basic filled primitives and quietly ignores much of the rest, including stroked paths. It does not warn, and it does not fail.
This is a build-configuration property of the ImageMagick binary, not of your SVG, so it reproduces on some machines and not others. A Homebrew imagemagick on macOS frequently lacks the delegate; many Linux distro packages have it.
Detection (one command, no test image)
$ magick -list format | grep -E '^ *(SVG|MSVG) '
SVG SVG rw+ Scalable Vector Graphics (XML 2.9.13)The parenthesised string names the renderer that will actually be used:
(XML 2.9.13)-> internal MSVG (a libxml2 version). Strokes will be dropped. Do not use this binary to rasterise SVG.(RSVG 2.x.y)-> librsvg. Fine.
Also useful: magick -version prints a Delegates (built-in): ... line. If rsvg is absent there, you are on MSVG.
Secondary confirmation without eyeballing anything, if you already have a known-good SVG: magick icon.svg -format %k info: reports the colour count. A stroke-only design that comes back with 2-15 colours (background + antialiased corner pixels) rather than the expected two-tone count has lost its linework.
Fix
Do not attempt to "repair" the SVG; MSVG is not going to render it. Use a real renderer:
Headless Chromium via Playwright is the most likely thing already sitting in a JS repo's devDependencies, and it is the same engine that will render the SVG for users. Give the root
<svg>aviewBoxand nowidth/height, then size it with CSS so one source file yields any raster size:import { chromium } from '@playwright/test'; const browser = await chromium.launch(); async function render(size) { const page = await browser.newPage({ viewport: { width: size, height: size } }); await page.setContent( `<style>html,body{margin:0}svg{display:block;width:100vw;height:100vh}</style>${svg}` ); const buf = await page.screenshot({ omitBackground: true }); await page.close(); return buf; }Tempting shortcut to avoid: stripping
width="64" height="64"off the root element with a regex like/\s(width|height)="64"/g. It will also match the background<rect width="64" height="64">and blank your artwork. Author the source with no root width/height instead.rsvg-convert(librsvg CLI),resvg, orsharpare the other reasonable choices.inkscape --export-type=pngworks but is a heavy dependency for a build step.
ImageMagick is still fine for the raster half of the job, e.g. assembling PNGs into a multi-frame .ico:
magick icon-256.png -define icon:auto-resize=64,48,32,16 favicon.ico. Only its SVG input path is suspect. (In a Node project, png-to-ico does the same thing with no system binary, which keeps the pipeline reproducible in CI.)
Why this is worth a guard
The output is a valid image of the right dimensions, so test -s, file, and magick identify all pass. Anything that only checks "did a PNG get written" will ship the broken asset. If a pipeline must rasterise SVG, assert on the renderer up front:
magick -list format | grep -q 'SVG.*RSVG' || { echo 'ImageMagick lacks librsvg; refusing to rasterise SVG' >&2; exit 1; }Verified on
ImageMagick 7.1.2-24 Q16-HDRI aarch64 (Homebrew, macOS arm64), Delegates (built-in): bzlib freetype heic jng jpeg lcms ltdl lzma png tiff webp xml zlib zstd — no rsvg. Same SVG renders correctly through Playwright 1.60 / Chromium at 16, 32, 48, 64 and 180 px.