d2phap/ImageGlass · error · InvalidDataException
IGE: Native codec '{CodecId}' returned status {status} for '
Error message
IGE: Native codec '{CodecId}' returned status {status} for '{filePath}'. What it means
Thrown by NativeCodecProxy.DecodeCore when the plugin's DecodeStaticRaster returns an IGStatus other than OK (and other than Canceled, which routes to cancellation instead). The actual status code is interpolated into the message so callers can see whether the plugin reported OutOfMemory, InvalidData, Unsupported, etc.
Source
Thrown at source/ImageGlass.Lib/Plugins/NativeCodecProxy.cs:416
var pathRef = new IGStringRef { Data = pPath, Length = filePath.Length };
status = _codecApi->DecodeStaticRaster(pathRef, frameIndex, &buffer, (void*)cancelHandle);
}
}
catch (Exception ex)
{
_failureManager.RecordSoftFailure(_plugin.PluginId,
$"managed exception during DecodeStaticRaster: {ex.Message}");
throw new InvalidDataException(
$"IGE: Native codec '{CodecId}' threw during decode of '{filePath}'.", ex);
}
if (status == IGStatus.Canceled)
{
token.ThrowIfCancellationRequested();
}
if (status != IGStatus.OK)
{
throw new InvalidDataException(
$"IGE: Native codec '{CodecId}' returned status {status} for '{filePath}'.");
}
bufferOwned = true;
// Wrap zero-copy: the SKImage takes ownership of the plugin buffer; when
// SkiaSharp disposes it, the release delegate calls back into the plugin's
// FreePixelBuffer (which the SDK contract requires to be thread-safe).
var image = WrapPluginBufferAsImage(in buffer, metadata.SkiaColorSpace);
ownershipTransferred = true;
// Synchronize the managed metadata dimensions with the decoded image.
if (metadata.Width == 0) metadata.Width = (uint)buffer.Width;
if (metadata.Height == 0) metadata.Height = (uint)buffer.Height;
if (metadata.OriginalWidth == 0) metadata.OriginalWidth = (uint)buffer.Width;
if (metadata.OriginalHeight == 0) metadata.OriginalHeight = (uint)buffer.Height;
// Build the final decode result the registry expects.
return new CodecDecodeResultView on GitHub (pinned to 4a3c4fecef)
Solutions
- Map the reported IGStatus to its meaning (InvalidData → corrupt file, Unsupported → feature/format mismatch, OutOfMemory → too large) and act accordingly.
- Try the file in another viewer/codec to confirm it is valid; if valid, the plugin may be missing support for a sub-format — report upstream.
- For OutOfMemory, retry on a smaller frame index or pre-downscale; for InvalidData, treat as unreadable and skip.
- Fall back to a built-in codec (Skia/Magick) for that extension if the plugin persistently fails.
Example fix
// before
if (status != IGStatus.OK)
throw new InvalidDataException($"IGE: Native codec '{CodecId}' returned status {status} for '{filePath}'.");
// after — translate status to a more specific message so callers can branch
if (status != IGStatus.OK)
{
var reason = status switch
{
IGStatus.OutOfMemory => "out of memory",
IGStatus.InvalidData => "corrupt or invalid input",
IGStatus.Unsupported => "unsupported feature",
_ => status.ToString(),
};
throw new InvalidDataException($"IGE: Native codec '{CodecId}' {reason} for '{filePath}' (status {status}).");
} Defensive patterns
Strategy: try-catch
Validate before calling
// Validate the file before invoking a heavyweight native decode.
var fi = new FileInfo(metadata.FilePath);
if (!fi.Exists || fi.Length == 0) throw new InvalidDataException("Empty/missing file"); Try / catch
try { return proxy.DecodeStatic(metadata, frame, token); }
catch (InvalidDataException ex) when (ex.Message.Contains("returned status"))
{
// Inspect the status text to branch: OutOfMemory → retry smaller; InvalidData → skip; Unsupported → fallback.
_log.Warn($"Plugin {proxy.CodecId} status on {metadata.FilePath}: {ex.Message}");
return BuiltInFallback(metadata);
} Prevention
- Treat IGStatus codes as the plugin's error vocabulary: branch on InvalidData vs Unsupported vs OutOfMemory.
- Keep a built-in codec fallback for extensions backed by a flaky plugin.
- Log the exact status code so plugin authors can reproduce the failure.
- Validate the file exists and is non-empty before handing it to native decode.
When it happens
Trigger: Produced at NativeCodecProxy.cs:416 when status != IGStatus.OK after the native call returned. The plugin ran to completion but reported a failure code; this is the plugin's normal error channel for malformed input or unsupported sub-formats.
Common situations: A corrupt or truncated image file (plugin returns InvalidData); a file that is technically the right extension but uses features the plugin cannot decode (Unsupported); the plugin ran out of memory (OutOfMemory); the file is zero-length or wrong format despite the extension.
Related errors
- Native codec '{CodecId}' does not support static-raster deco
- IGE: Native codec '{proxy.CodecId}' returned status {status}
- IGE: Native codec '{CodecId}' was unloaded.
- IGE: Native codec '{CodecId}' threw during decode of '{fileP
- IGE: Native codec '{CodecId}' returned an invalid pixel buff
AI-assisted analysis of d2phap/ImageGlass@4a3c4fecef (2026-08-13).
Data as JSON: /api/errors/7e89ab62fd6ebcb1.
Report an issue: GitHub.