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 CodecDecodeResult

View on GitHub (pinned to 4a3c4fecef)

Solutions

  1. Map the reported IGStatus to its meaning (InvalidData → corrupt file, Unsupported → feature/format mismatch, OutOfMemory → too large) and act accordingly.
  2. 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.
  3. For OutOfMemory, retry on a smaller frame index or pre-downscale; for InvalidData, treat as unreadable and skip.
  4. 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

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


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