{"record":{"id":"40a63a5e788dec56","repo":"d2phap/ImageGlass","slug":"ige-native-codec-codecid-threw-during-decode","errorCode":null,"errorMessage":"IGE: Native codec '{CodecId}' threw during decode of '{filePath}'.","messagePattern":"IGE: Native codec '(.+?)' threw during decode of '(.+?)'\\.","errorType":"exception","errorClass":"InvalidDataException","httpStatus":null,"severity":"error","filePath":"source/ImageGlass.Lib/Plugins/NativeCodecProxy.cs","lineNumber":406,"sourceCode":"        var ownershipTransferred = false;\n\n        try\n        {\n            IGStatus status;\n            try\n            {\n                // Ask the plugin to decode the requested frame into its ABI buffer struct.\n                fixed (char* pPath = filePath)\n                {\n                    var pathRef = new IGStringRef { Data = pPath, Length = filePath.Length };\n                    status = _codecApi->DecodeStaticRaster(pathRef, frameIndex, &buffer, (void*)cancelHandle);\n                }\n            }\n            catch (Exception ex)\n            {\n                _failureManager.RecordSoftFailure(_plugin.PluginId,\n                    $\"managed exception during DecodeStaticRaster: {ex.Message}\");\n                throw new InvalidDataException(\n                    $\"IGE: Native codec '{CodecId}' threw during decode of '{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 '{CodecId}' returned status {status} for '{filePath}'.\");\n            }\n            bufferOwned = true;\n\n            // Wrap zero-copy: the SKImage takes ownership of the plugin buffer; when\n            // SkiaSharp disposes it, the release delegate calls back into the plugin's\n            // FreePixelBuffer (which the SDK contract requires to be thread-safe).\n            var image = WrapPluginBufferAsImage(in buffer, metadata.SkiaColorSpace);","sourceCodeStart":388,"sourceCodeEnd":424,"githubUrl":"https://github.com/d2phap/ImageGlass/blob/4a3c4feceffc5a8bb5e56ba836509634aaae47a9/source/ImageGlass.Lib/Plugins/NativeCodecProxy.cs#L388-L424","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["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.","Rebuild the plugin against the exact host ABI (struct sizes, calling convention, SDK version) — mismatched structs are the most common cause.","Verify the plugin DLL is intact and built for the same architecture (x64/ARM64) as the host.","If the inner exception is AccessViolation, suspect a plugin bug: report to the plugin author with the file that triggered it."],"exampleFix":"// before\ncatch (Exception ex)\n{\n    _failureManager.RecordSoftFailure(_plugin.PluginId, $\"managed exception during DecodeStaticRaster: {ex.Message}\");\n    throw new InvalidDataException($\"IGE: Native codec '{CodecId}' threw during decode of '{filePath}'.\", ex);\n}\n\n// caller — distinguish thrown-during-decode from returned-bad-status so logs are actionable\ncatch (InvalidDataException ex) when (ex.InnerException is AccessViolationException)\n{\n    _log.Error($\"Plugin {CodecId} access violation on {filePath}; disabling codec for session.\");\n    _failureManager.RecordHardFailure(_plugin.PluginId);\n    throw;\n}","handlingStrategy":"try-catch","validationCode":"// Before decode, sanity-check inputs the plugin depends on.\nif (string.IsNullOrEmpty(metadata.FilePath) || !File.Exists(metadata.FilePath))\n    throw new FileNotFoundException(metadata.FilePath);\nif (proxy.Plugin.LiveToken is null) throw new InvalidOperationException(\"Plugin not loaded\");","typeGuard":null,"tryCatchPattern":"try { return proxy.DecodeStatic(metadata, frame, token); }\ncatch (InvalidDataException ex) when (ex.Message.Contains(\"threw during decode\") && ex.InnerException is AccessViolationException)\n{ _failureManager.RecordHardFailure(proxy.Plugin.PluginId); _log.Error($\"Plugin {proxy.CodecId} AV on {metadata.FilePath}\"); throw; }","preventionTips":["Build plugins against the exact host ABI (struct layout, calling convention, SDK version).","Verify plugin and host share the same architecture (x64/ARM64).","Capture and read ex.InnerException to classify ABI faults vs plugin logic faults.","Quarantine a plugin after repeated access violations instead of letting it keep faulting."],"tags":["plugin","codec","native","abi","access-violation"],"backgroundTag":null,"analyzedSha":"4a3c4feceffc5a8bb5e56ba836509634aaae47a9","analyzedAt":"2026-08-13T16:58:15.523Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}