d2phap/ImageGlass · error · InvalidDataException
IGE: Native codec '{CodecId}' returned an invalid pixel buff
Error message
IGE: Native codec '{CodecId}' returned an invalid pixel buffer. What it means
Thrown by NativeCodecProxy.WrapPluginBufferAsImage when the IGPixelBuffer returned by a plugin fails basic validation: Data is null, or Width/Height is zero or negative. The host refuses to hand such a buffer to Skia because SKImage.FromPixels on a null/empty buffer is undefined behavior.
Source
Thrown at source/ImageGlass.Lib/Plugins/NativeCodecProxy.cs:800
public void Dispose()
{
if (Frame.OwnsImage) Frame.Image.Dispose();
}
}
/// <summary>
/// Wraps a plugin-owned <see cref="IGPixelBuffer"/> in an <see cref="SKImage"/>
/// without copying the pixels. The returned image owns the plugin buffer:
/// disposing the image calls back into the plugin's <c>FreePixelBuffer</c>
/// via the release delegate (which the SDK contract requires to be thread-safe).
/// </summary>
internal SKImage WrapPluginBufferAsImage(in IGPixelBuffer buffer, SKColorSpace? srcColorSpace)
{
// Validate the buffer before we hand it to Skia.
if (buffer.Data == null || buffer.Width <= 0 || buffer.Height <= 0)
{
throw new InvalidDataException(
$"IGE: Native codec '{CodecId}' returned an invalid pixel buffer.");
}
var (colorType, alphaType) = MapPixelFormat((IGPixelFormat)buffer.PixelFormat);
if (colorType == SKColorType.Unknown)
{
throw new InvalidDataException(
$"IGE: Native codec '{CodecId}' returned an unsupported pixel format ({buffer.PixelFormat}).");
}
var info = new SKImageInfo(buffer.Width, buffer.Height, colorType, alphaType);
if (srcColorSpace is not null)
{
info = info.WithColorSpace(srcColorSpace);
}
// Carrier holds the plugin codec API + a copy of the buffer descriptor so
// SkiaSharp can hand the pointer back to the plugin on dispose.View on GitHub (pinned to 4a3c4fecef)
Solutions
- Report the bug to the plugin author: the plugin returned IGStatus.OK with an empty/null pixel buffer, which violates the SDK contract.
- Rebuild the plugin against the current SDK and verify its DecodeStaticRaster populates IGPixelBuffer.Data, .Width, .Height, .Stride on the success path.
- Disable the plugin for the affected format and let a built-in codec handle the file.
- If authoring a plugin, add an assertion at the end of DecodeStaticRaster that the buffer is fully populated before returning IGStatus.OK.
Example fix
// before
if (buffer.Data == null || buffer.Width <= 0 || buffer.Height <= 0)
throw new InvalidDataException($"IGE: Native codec '{CodecId}' returned an invalid pixel buffer.");
// after — include the bad fields so the plugin author can pinpoint the unset slot
if (buffer.Data == null || buffer.Width <= 0 || buffer.Height <= 0)
throw new InvalidDataException(
$"IGE: Native codec '{CodecId}' returned an invalid pixel buffer " +
$"(Data={(buffer.Data == null ? "null" : "ok")}, Width={buffer.Width}, Height={buffer.Height})."); Defensive patterns
Strategy: validation
Validate before calling
// Validate the plugin-returned buffer before passing it to Skia.
static bool IsValidPluginBuffer(in IGPixelBuffer b) =>
b.Data != null && b.Width > 0 && b.Height > 0; Type guard
static bool IsValidPluginBuffer(in IGPixelBuffer b) =>
b.Data != null && b.Width > 0 && b.Height > 0; Try / catch
try { image = proxy.WrapPluginBufferAsImage(in buffer, colorSpace); }
catch (InvalidDataException ex) when (ex.Message.Contains("invalid pixel buffer"))
{ _failureManager.RecordSoftFailure(proxy.Plugin.PluginId, "empty pixel buffer on OK"); return BuiltInFallback(metadata); } Prevention
- When authoring a plugin, assert at the end of DecodeStaticRaster that Data/Width/Height are set before returning OK.
- Treat a buffer that is empty after IGStatus.OK as a plugin contract violation — report upstream.
- Build plugins against the current SDK so the IGPixelBuffer field order matches.
- Keep a built-in codec fallback so a buggy plugin buffer does not strand the file.
When it happens
Trigger: Produced at NativeCodecProxy.cs:800 inside WrapPluginBufferAsImage, called from DecodeCore after a plugin's DecodeStaticRaster reported IGStatus.OK but filled the IGPixelBuffer with a null Data pointer or non-positive dimensions. The plugin lied: it returned success but did not produce a usable buffer.
Common situations: Plugin bug: decode succeeded internally but the buffer struct was not populated (forgot to set Data, or set Width/Height from a zero-sized frame); plugin returned a metadata-only frame; plugin's static decode path is incomplete and zeroed the struct on success; ABI mismatch where Width/Height land at wrong offsets.
Related errors
- Native codec '{CodecId}' does not support static-raster deco
- IGE: Native codec '{CodecId}' threw during decode of '{fileP
- IGE: Native codec '{CodecId}' returned an unsupported pixel
- IGE: Native codec '{proxy.CodecId}' is missing one of the an
- IGE: Native codec '{proxy.CodecId}' reported zero frames for
AI-assisted analysis of d2phap/ImageGlass@4a3c4fecef (2026-08-13).
Data as JSON: /api/errors/e46d190aaf1359e3.
Report an issue: GitHub.