Troubleshooting
Runtime errors and their fixes.
Deployment
Section titled “Deployment””Unable to load DLL ‘pragmatic_native’” or DllNotFoundException
Section titled “”Unable to load DLL ‘pragmatic_native’” or DllNotFoundException”The native binary isn’t findable. In order of likelihood:
- Wrong RID / unsupported platform. The NuGet ships
win-x64today; Linux and macOS need a locally-built binary. See native-deployment.md. - Alpine Linux (musl libc). The native library requires glibc. Use a Debian/Ubuntu image, or build the native library for musl.
- Self-contained publish missing the runtime folder. Ensure
dotnet publish -r <rid> --self-containedand checkpublish/runtimes/<rid>/native/contains the binary. - Framework-dependent publish lost the file. A custom
Copystep in the build may have excludedruntimes/— verify withls bin/Release/net10.0/runtimes/.
DllNotFoundException on first request but not in unit tests
Section titled “DllNotFoundException on first request but not in unit tests”Tests run in the project’s output folder where runtimes/ is present. The published artifact may have a different structure. Check /runtimes/<rid>/native/ inside the publish output.
Version mismatch between managed DLL and native binary
Section titled “Version mismatch between managed DLL and native binary”Symptom: the managed code loads, but the first FFI call panics or segfaults.
Cause: you built the native library from a different commit than the managed Pragmatic.Imaging.dll.
Fix: match the native library’s Cargo.toml version with the NuGet package version, or rebuild both from the same commit.
Runtime
Section titled “Runtime”ImagingException { Reason = DecodeFailed }
Section titled “ImagingException { Reason = DecodeFailed }”The input isn’t a valid image in a supported format. Check:
ImageInfo.FromBytes(input)to see what the header identifies- File is complete (truncated downloads produce
DecodeFailed) - Format is in
ImagingOptions.AllowedFormats
ImagingException { Reason = MaxWidthExceeded / MaxHeightExceeded / MaxDecodedBytesExceeded }
Section titled “ImagingException { Reason = MaxWidthExceeded / MaxHeightExceeded / MaxDecodedBytesExceeded }”The input violates the safety limits. Either:
- Legitimate large image → relax
ImagingOptions - Adversarial input → log and reject (this is the feature working)
ImagingException { Reason = UnsupportedFormat }
Section titled “ImagingException { Reason = UnsupportedFormat }”You tried to encode into a format the library doesn’t support for output (e.g. AVIF, TIFF, GIF). Supported output: PNG, JPEG, WebP, BMP.
ImagingException { Reason = InvalidArgument }
Section titled “ImagingException { Reason = InvalidArgument }”Parameters don’t make sense:
Crop(x, y, w, h)extends past the image boundsRotate(45)— only 0/90/180/270 allowedResize(0, 0)— dimensions must be positive
The exception message identifies which argument failed.
Output file is empty (0 bytes)
Section titled “Output file is empty (0 bytes)”- Did you dispose the pipeline before flushing the output stream?
EncodeTowrites to the stream immediately, so it’s safe to dispose the pipeline right after. - Did the output stream get closed before EncodeTo had a chance to write? Use
usingaround the output only afterEncodeToreturns.
// ✅using var pipe = ImagePipeline.Load(bytes);using (var output = File.Create("out.png")){ pipe.Resize(400, 400).EncodeTo(output, ImageFormat.Png);} // output stream disposed here, after EncodeTo completedJPEG output looks blocky / low quality
Section titled “JPEG output looks blocky / low quality”You probably passed a low quality value. quality: 50 is visibly degraded for photos; 75 is acceptable; 85 is typical for production; 95+ is archival.
WebP output is smaller than expected but takes forever
Section titled “WebP output is smaller than expected but takes forever”WebP at quality: 100 uses the (slow) “near-lossless” path. Drop to 90-95 for a dramatic speed-up with minimal visual difference.
Memory
Section titled “Memory”Process RSS keeps growing under load
Section titled “Process RSS keeps growing under load”Check that every ImagePipeline.Load has a matching Dispose. Without disposal, native memory leaks until the .NET finaliser runs — which can be minutes under GC pressure.
Pattern to look for: pipelines stored in fields or captured by long-lived closures without a dispose path.
OutOfMemoryException under high-concurrency load
Section titled “OutOfMemoryException under high-concurrency load”Too many pipelines alive at once. Cap concurrency:
var batch = new ImageBatch(maxConcurrency: 4); // rather than Task.WhenAll with 100 itemsRule of thumb: one active pipeline can hold ~(width × height × 4 bytes) native. An 8000×8000 pipeline is ~250MB.
Performance
Section titled “Performance”Batch processing slower than sequential
Section titled “Batch processing slower than sequential”Likely oversubscribed. CPU-bound native work doesn’t scale beyond physical cores.
// Too many on a 4-core machine → each contends for CPU and memory bandwidthvar batch = new ImageBatch(maxConcurrency: 32);
// Typically optimalvar batch = new ImageBatch(maxConcurrency: Environment.ProcessorCount);First call is slow, subsequent calls are fast
Section titled “First call is slow, subsequent calls are fast”The native library lazily initialises on first use. Pre-warm at startup if latency matters:
// In Program.cs startupusing var _ = ImagePipeline.Load(TinyWarmupImage); // triggers native loadLanczos3 resize is slow for thumbnails
Section titled “Lanczos3 resize is slow for thumbnails”For thumbnails where quality at pixel level doesn’t matter, CatmullRom is ~2× faster with imperceptible difference at small sizes:
pipe.Thumbnail(200, 200, ResizeFilter.CatmullRom);Reserve Lanczos3 for hero images and large outputs.
Outputs look wrong
Section titled “Outputs look wrong”Image is rotated 90°
Section titled “Image is rotated 90°”The source has an EXIF orientation tag (common from phone cameras). Re-encoding strips EXIF, so the stored orientation is lost. If the native decoder didn’t honour the EXIF orientation during decode, you’ll see the raw pixel rotation.
Fix: before transformation, read ImageInfo and apply a Rotate(...) explicitly based on the EXIF orientation. The library doesn’t auto-rotate today.
Colours look off
Section titled “Colours look off”All pixels are assumed sRGB. If the source is wide-gamut (P3, AdobeRGB), colours will shift when re-encoded as sRGB.
There’s no colour-space conversion today; if you need it, transcode to sRGB before feeding the pipeline.
Transparency becomes black in JPEG output
Section titled “Transparency becomes black in JPEG output”JPEG has no alpha channel. Transparent pixels composite against black. If this isn’t what you want, flatten against a background colour before encoding (not currently a first-class operation — preprocess in ImageSharp if necessary).
Still stuck?
Section titled “Still stuck?”- The corresponding sample in
samples/Pragmatic.Imaging.Samples/runs end-to-end and can be diffed against your code. - File an issue with a minimal reproducer, the RID, and the
ImagingException.Reasonif applicable.