{"record":{"id":"0b4e53a7ec7161d0","repo":"d2phap/ImageGlass","slug":"ige-native-codec-proxy-codecid-reported-zero","errorCode":null,"errorMessage":"IGE: Native codec '{proxy.CodecId}' reported zero frames for '{metadata.FilePath}'.","messagePattern":"IGE: Native codec '(.+?)' reported zero frames for '(.+?)'\\.","errorType":"exception","errorClass":"InvalidDataException","httpStatus":null,"severity":"error","filePath":"source/ImageGlass.Lib/Plugins/NativePluginAnimator.cs","lineNumber":111,"sourceCode":"                    $\"managed exception during GetAnimationInfo: {ex.Message}\");\n                throw new InvalidDataException(\n                    $\"IGE: Native codec '{proxy.CodecId}' threw during GetAnimationInfo of '{metadata.FilePath}'.\", ex);\n            }\n\n            if (status == IGStatus.Canceled)\n            {\n                token.ThrowIfCancellationRequested();\n            }\n            if (status != IGStatus.OK)\n            {\n                throw new InvalidDataException(\n                    $\"IGE: Native codec '{proxy.CodecId}' returned status {status} for GetAnimationInfo of '{metadata.FilePath}'.\");\n            }\n            infoOwned = true;\n\n            if (info.FrameCount <= 0 || info.Frames == null)\n            {\n                throw new InvalidDataException(\n                    $\"IGE: Native codec '{proxy.CodecId}' reported zero frames for '{metadata.FilePath}'.\");\n            }\n\n            // PHASE 2: copy per-frame timing into the SKCodecFrameInfo[] expected by AnimatorImpl.\n            // Only Duration + AlphaType are meaningful here -- the host does not composite.\n            var frames = new SKCodecFrameInfo[info.FrameCount];\n            for (var i = 0; i < info.FrameCount; i++)\n            {\n                var f = info.Frames[i];\n                frames[i] = new SKCodecFrameInfo\n                {\n                    Duration = f.DurationMs,\n                    AlphaType = f.HasAlpha != 0 ? SKAlphaType.Unpremul : SKAlphaType.Opaque,\n                };\n            }\n\n            var animator = new NativePluginAnimator(proxy, metadata, frames)\n            {","sourceCodeStart":93,"sourceCodeEnd":129,"githubUrl":"https://github.com/d2phap/ImageGlass/blob/4a3c4feceffc5a8bb5e56ba836509634aaae47a9/source/ImageGlass.Lib/Plugins/NativePluginAnimator.cs#L93-L129","documentation":"Thrown by NativePluginAnimator.Create when the plugin returned IGStatus.OK from GetAnimationInfo but the IGAnimationInfo struct is empty: FrameCount <= 0 or the Frames pointer is null. The plugin claimed success but produced no frames, so the host cannot build a frame timing array.","triggerScenarios":"Produced at NativePluginAnimator.cs:111 when info.FrameCount <= 0 || info.Frames == null after a successful GetAnimationInfo. The plugin reported OK but its animation info is structurally empty.","commonSituations":"Plugin bug: GetAnimationInfo returns OK without populating Frames/FrameCount (e.g. allocates the info struct but does not fill the frame array); ABI mismatch swapping FrameCount with another field so it reads as zero; plugin parsed a file with zero frames but still returned OK instead of InvalidData; plugin's animation-info allocator failed silently.","solutions":["Report to the plugin author: GetAnimationInfo returned OK with FrameCount<=0 or Frames=null, which violates the contract.","Rebuild the plugin and verify its GetAnimationInfo populates IGAnimationInfo.Frames (a caller-allocated array of IGAnimationFrameInfo) and sets FrameCount > 0 on the success path.","Verify the IGAnimationInfo struct field order matches the SDK header in both plugin and host.","Disable the plugin and decode the file with a built-in animator."],"exampleFix":"// before\nif (info.FrameCount <= 0 || info.Frames == null)\n    throw new InvalidDataException($\"IGE: Native codec '{proxy.CodecId}' reported zero frames for '{metadata.FilePath}'.\");\n\n// after — name which field was bad so the plugin author can locate it\nif (info.FrameCount <= 0 || info.Frames == null)\n    throw new InvalidDataException(\n        $\"IGE: Native codec '{proxy.CodecId}' reported zero frames for '{metadata.FilePath}' \" +\n        $\"(FrameCount={info.FrameCount}, Frames={(info.Frames == null ? \"null\" : \"ok\")}).\");","handlingStrategy":"validation","validationCode":"// After GetAnimationInfo returns OK, sanity-check the populated struct.\nif (info.FrameCount <= 0 || info.Frames == null)\n    throw new InvalidDataException(\"Plugin returned OK but no frames\");","typeGuard":"static bool HasFrames(in IGAnimationInfo info) =>\n    info.FrameCount > 0 && info.Frames != null;","tryCatchPattern":"try { return NativePluginAnimator.Create(proxy, metadata, token); }\ncatch (InvalidDataException ex) when (ex.Message.Contains(\"zero frames\"))\n{ _failureManager.RecordSoftFailure(proxy.Plugin.PluginId, \"zero frames on OK\"); return null; }","preventionTips":["When authoring a plugin, populate Frames and FrameCount before returning OK from GetAnimationInfo.","Match IGAnimationInfo field order between plugin and host SDK exactly.","Treat an empty IGAnimationInfo on OK as a contract violation and report upstream.","Fall back to a built-in animator when the plugin reports zero frames."],"tags":["plugin","codec","native","animation","abi"],"backgroundTag":null,"analyzedSha":"4a3c4feceffc5a8bb5e56ba836509634aaae47a9","analyzedAt":"2026-08-13T16:58:15.523Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}