{"record":{"id":"e46d190aaf1359e3","repo":"d2phap/ImageGlass","slug":"ige-native-codec-codecid-returned-an-invalid","errorCode":null,"errorMessage":"IGE: Native codec '{CodecId}' returned an invalid pixel buffer.","messagePattern":"IGE: Native codec '(.+?)' returned an invalid pixel buffer\\.","errorType":"exception","errorClass":"InvalidDataException","httpStatus":null,"severity":"error","filePath":"source/ImageGlass.Lib/Plugins/NativeCodecProxy.cs","lineNumber":800,"sourceCode":"        public void Dispose()\n        {\n            if (Frame.OwnsImage) Frame.Image.Dispose();\n        }\n    }\n\n\n    /// <summary>\n    /// Wraps a plugin-owned <see cref=\"IGPixelBuffer\"/> in an <see cref=\"SKImage\"/>\n    /// without copying the pixels. The returned image owns the plugin buffer:\n    /// disposing the image calls back into the plugin's <c>FreePixelBuffer</c>\n    /// via the release delegate (which the SDK contract requires to be thread-safe).\n    /// </summary>\n    internal SKImage WrapPluginBufferAsImage(in IGPixelBuffer buffer, SKColorSpace? srcColorSpace)\n    {\n        // Validate the buffer before we hand it to Skia.\n        if (buffer.Data == null || buffer.Width <= 0 || buffer.Height <= 0)\n        {\n            throw new InvalidDataException(\n                $\"IGE: Native codec '{CodecId}' returned an invalid pixel buffer.\");\n        }\n\n        var (colorType, alphaType) = MapPixelFormat((IGPixelFormat)buffer.PixelFormat);\n        if (colorType == SKColorType.Unknown)\n        {\n            throw new InvalidDataException(\n                $\"IGE: Native codec '{CodecId}' returned an unsupported pixel format ({buffer.PixelFormat}).\");\n        }\n\n        var info = new SKImageInfo(buffer.Width, buffer.Height, colorType, alphaType);\n        if (srcColorSpace is not null)\n        {\n            info = info.WithColorSpace(srcColorSpace);\n        }\n\n        // Carrier holds the plugin codec API + a copy of the buffer descriptor so\n        // SkiaSharp can hand the pointer back to the plugin on dispose.","sourceCodeStart":782,"sourceCodeEnd":818,"githubUrl":"https://github.com/d2phap/ImageGlass/blob/4a3c4feceffc5a8bb5e56ba836509634aaae47a9/source/ImageGlass.Lib/Plugins/NativeCodecProxy.cs#L782-L818","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nif (buffer.Data == null || buffer.Width <= 0 || buffer.Height <= 0)\n    throw new InvalidDataException($\"IGE: Native codec '{CodecId}' returned an invalid pixel buffer.\");\n\n// after — include the bad fields so the plugin author can pinpoint the unset slot\nif (buffer.Data == null || buffer.Width <= 0 || buffer.Height <= 0)\n    throw new InvalidDataException(\n        $\"IGE: Native codec '{CodecId}' returned an invalid pixel buffer \" +\n        $\"(Data={(buffer.Data == null ? \"null\" : \"ok\")}, Width={buffer.Width}, Height={buffer.Height}).\");","handlingStrategy":"validation","validationCode":"// Validate the plugin-returned buffer before passing it to Skia.\nstatic bool IsValidPluginBuffer(in IGPixelBuffer b) =>\n    b.Data != null && b.Width > 0 && b.Height > 0;","typeGuard":"static bool IsValidPluginBuffer(in IGPixelBuffer b) =>\n    b.Data != null && b.Width > 0 && b.Height > 0;","tryCatchPattern":"try { image = proxy.WrapPluginBufferAsImage(in buffer, colorSpace); }\ncatch (InvalidDataException ex) when (ex.Message.Contains(\"invalid pixel buffer\"))\n{ _failureManager.RecordSoftFailure(proxy.Plugin.PluginId, \"empty pixel buffer on OK\"); return BuiltInFallback(metadata); }","preventionTips":["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."],"tags":["plugin","codec","native","abi","pixel-buffer"],"backgroundTag":null,"analyzedSha":"4a3c4feceffc5a8bb5e56ba836509634aaae47a9","analyzedAt":"2026-08-13T16:58:15.523Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}