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

  1. 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.
  2. Rebuild the plugin against the exact host ABI (struct sizes, calling convention, SDK version) — mismatched structs are the most common cause.
  3. Verify the plugin DLL is intact and built for the same architecture (x64/ARM64) as the host.
  4. 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

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


AI-assisted analysis of d2phap/ImageGlass@4a3c4fecef (2026-08-13). Data as JSON: /api/errors/40a63a5e788dec56. Report an issue: GitHub.