Skip to content

Troubleshooting

Runtime errors and their fixes.


”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:

  1. Wrong RID / unsupported platform. The NuGet ships win-x64 today; Linux and macOS need a locally-built binary. See native-deployment.md.
  2. Alpine Linux (musl libc). The native library requires glibc. Use a Debian/Ubuntu image, or build the native library for musl.
  3. Self-contained publish missing the runtime folder. Ensure dotnet publish -r <rid> --self-contained and check publish/runtimes/<rid>/native/ contains the binary.
  4. Framework-dependent publish lost the file. A custom Copy step in the build may have excluded runtimes/ — verify with ls 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.


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 bounds
  • Rotate(45) — only 0/90/180/270 allowed
  • Resize(0, 0) — dimensions must be positive

The exception message identifies which argument failed.

  • Did you dispose the pipeline before flushing the output stream? EncodeTo writes 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 using around the output only after EncodeTo returns.
// ✅
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 completed

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.


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 items

Rule of thumb: one active pipeline can hold ~(width × height × 4 bytes) native. An 8000×8000 pipeline is ~250MB.


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 bandwidth
var batch = new ImageBatch(maxConcurrency: 32);
// Typically optimal
var 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 startup
using var _ = ImagePipeline.Load(TinyWarmupImage); // triggers native load

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.


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.

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.

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).


  • 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.Reason if applicable.