d2phap/ImageGlass · error · InvalidDataException
IGE: Native codec '{CodecId}' threw during decode of '{fileP
Error message
IGE: Native codec '{CodecId}' threw during decode of '{filePath}'. What it means
Thrown by NativeCodecProxy.DecodeCore when the managed call into _codecApi->DecodeStaticRaster throws a managed exception (e.g. the function pointer thunk raised because of a bad ABI marshalling, access violation wrapped by the runtime, or a runtime-injected failure). The original exception is captured as InnerException, a soft failure is recorded via _failureManager.RecordSoftFailure, and an InvalidDataException is thrown to the caller with the codec ID and file path.
Source
Thrown at source/ImageGlass.Lib/Plugins/NativeCodecProxy.cs:406
var ownershipTransferred = false;
try
{
IGStatus status;
try
{
// Ask the plugin to decode the requested frame into its ABI buffer struct.
fixed (char* pPath = filePath)
{
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);View on GitHub (pinned to 4a3c4fecef)
Solutions
- Read ex.InnerException (the original exception) and the recorded soft-failure message to identify whether it is an access violation, ABI mismatch, or marshalling fault.
- Rebuild the plugin against the exact host ABI (struct sizes, calling convention, SDK version) — mismatched structs are the most common cause.
- Verify the plugin DLL is intact and built for the same architecture (x64/ARM64) as the host.
- If the inner exception is AccessViolation, suspect a plugin bug: report to the plugin author with the file that triggered it.
Example fix
// before
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);
}
// caller — distinguish thrown-during-decode from returned-bad-status so logs are actionable
catch (InvalidDataException ex) when (ex.InnerException is AccessViolationException)
{
_log.Error($"Plugin {CodecId} access violation on {filePath}; disabling codec for session.");
_failureManager.RecordHardFailure(_plugin.PluginId);
throw;
} Defensive patterns
Strategy: try-catch
Validate before calling
// Before decode, sanity-check inputs the plugin depends on.
if (string.IsNullOrEmpty(metadata.FilePath) || !File.Exists(metadata.FilePath))
throw new FileNotFoundException(metadata.FilePath);
if (proxy.Plugin.LiveToken is null) throw new InvalidOperationException("Plugin not loaded"); Try / catch
try { return proxy.DecodeStatic(metadata, frame, token); }
catch (InvalidDataException ex) when (ex.Message.Contains("threw during decode") && ex.InnerException is AccessViolationException)
{ _failureManager.RecordHardFailure(proxy.Plugin.PluginId); _log.Error($"Plugin {proxy.CodecId} AV on {metadata.FilePath}"); throw; } Prevention
- Build plugins against the exact host ABI (struct layout, calling convention, SDK version).
- Verify plugin and host share the same architecture (x64/ARM64).
- Capture and read ex.InnerException to classify ABI faults vs plugin logic faults.
- Quarantine a plugin after repeated access violations instead of letting it keep faulting.
When it happens
Trigger: Produced inside the try around the native DecodeStaticRaster call (NativeCodecProxy.cs:398-405). Triggers when the native-to-managed thunk faults, or when the runtime raises an exception crossing the unsafe call boundary.
Common situations: ABI mismatch between plugin and host (struct layout, calling convention); a corrupt or partial plugin DLL; the plugin dereferenced a null/freed pointer and the runtime surfaced it as AccessViolation; plugin built for a different pointer-width; file path with characters that break the IGStringRef marshalling.
Related errors
- Native codec '{CodecId}' does not support static-raster deco
- IGE: Native codec '{CodecId}' returned an invalid pixel buff
- IGE: Native codec '{proxy.CodecId}' is missing one of the an
- IGE: Native codec '{proxy.CodecId}' threw during GetAnimatio
- IGE: Native codec '{proxy.CodecId}' reported zero frames for
AI-assisted analysis of d2phap/ImageGlass@4a3c4fecef (2026-08-13).
Data as JSON: /api/errors/40a63a5e788dec56.
Report an issue: GitHub.