{"record":{"id":"ddbc4f38e6811339","repo":"d2phap/ImageGlass","slug":"cannot-decode-webp","errorCode":null,"errorMessage":"Cannot decode WebP","messagePattern":"Cannot decode WebP","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"v9/Components/ImageGlass.WebP/libwebp.cs","lineNumber":206,"sourceCode":"    {\n        return WebPGetInfo_x64(data, (UIntPtr)data_size, out width, out height);\n    }\n    [DllImport(\"libwebp.dll\", CallingConvention = CallingConvention.Cdecl, EntryPoint = \"WebPGetInfo\")]\n    private static extern int WebPGetInfo_x64([InAttribute()] IntPtr data, UIntPtr data_size, out int width, out int height);\n\n\n\n\n    /// <summary>Decode WEBP image pointed to by *data and returns BGR samples into a preallocated buffer</summary>\n    /// <param name=\"data\">Pointer to WebP image data</param>\n    /// <param name=\"data_size\">This is the size of the memory block pointed to by data containing the image data</param>\n    /// <param name=\"output_buffer\">Pointer to decoded WebP image</param>\n    /// <param name=\"output_buffer_size\">Size of allocated buffer</param>\n    /// <param name=\"output_stride\">Specifies the distance between scan lines</param>\n    internal static void WebPDecodeBGRInto(IntPtr data, int data_size, IntPtr output_buffer, int output_buffer_size, int output_stride)\n    {\n        if (WebPDecodeBGRInto_x64(data, (UIntPtr)data_size, output_buffer, output_buffer_size, output_stride) == null)\n            throw new InvalidOperationException(\"Cannot decode WebP\");\n    }\n    [DllImport(\"libwebp.dll\", CallingConvention = CallingConvention.Cdecl, EntryPoint = \"WebPDecodeBGRInto\")]\n    private static extern IntPtr? WebPDecodeBGRInto_x64([InAttribute()] IntPtr data, UIntPtr data_size, IntPtr output_buffer, int output_buffer_size, int output_stride);\n\n\n\n\n    /// <summary>Decode WEBP image pointed to by *data and returns BGRA samples into a preallocated buffer</summary>\n    /// <param name=\"data\">Pointer to WebP image data</param>\n    /// <param name=\"data_size\">This is the size of the memory block pointed to by data containing the image data</param>\n    /// <param name=\"output_buffer\">Pointer to decoded WebP image</param>\n    /// <param name=\"output_buffer_size\">Size of allocated buffer</param>\n    /// <param name=\"output_stride\">Specifies the distance between scan lines</param>\n    internal static void WebPDecodeBGRAInto(IntPtr data, int data_size, IntPtr output_buffer, int output_buffer_size, int output_stride)\n    {\n        if (WebPDecodeBGRAInto_x64(data, (UIntPtr)data_size, output_buffer, output_buffer_size, output_stride) == null)\n            throw new InvalidOperationException(\"Can not decode WebP\");\n    }","sourceCodeStart":188,"sourceCodeEnd":224,"githubUrl":"https://github.com/d2phap/ImageGlass/blob/4a3c4feceffc5a8bb5e56ba836509634aaae47a9/v9/Components/ImageGlass.WebP/libwebp.cs#L188-L224","documentation":"Thrown by WebPDecodeBGRInto in ImageGlass.WebP when the native libwebp function of the same name returns NULL. The C libwebp API returns the output_buffer pointer on success and NULL on failure, so a null result means libwebp could not decode the supplied bytes into the BGR buffer. The C# wrapper marshals that pointer as Nullable<IntPtr> (WebPDecodeBGRInto_x64) and converts the null case into this InvalidOperationException. It is the decode path used by WebPWrapper.Decode for 24-bpp (no-alpha) WebP images.","triggerScenarios":"Calling WebPWrapper.Decode (or LibWebp.WebPDecodeBGRInto directly) with a byte[] that is truncated, corrupted, or not actually WebP; passing a data_size that disagrees with the real buffer length; an output_buffer too small for stride*height; an output_stride that does not match the locked BitmapData.Stride; or running against a libwebp.dll whose ABI/struct version differs from what the wrapper was compiled for.","commonSituations":"A .webp downloaded over an interrupted connection is truncated; a file mislabeled .webp is fed in; rawWebP is mutated on another thread while pinned; the wrong bitness of libwebp.dll (x86 vs x64) is deployed; or libwebp was upgraded without recompiling the wrapper so WEBP_DECODER_ABI_VERSION no longer matches.","solutions":["Verify the bytes are a complete, valid WebP stream (bytes 0-3 are 'RIFF', bytes 8-11 are 'WEBP', chunk sizes consistent) before decoding.","Confirm libwebp.dll matches the process architecture (x64 build needs the x64 dll) and is the same major/ABI version the wrapper targets.","Check that output_buffer_size >= stride * height and that output_stride equals the BitmapData.Stride actually passed.","Ensure the pinned rawWebP buffer is not modified on another thread during decode; decode from a defensive copy.","If the stream may be animated or uses advanced features, route it through the WebPDecoderConfig advanced decode path instead of the single-frame BGRInto call."],"exampleFix":"// before\nLibWebp.WebPDecodeBGRInto(ptrData, rawWebP.Length, bmpData.Scan0, outputSize, bmpData.Stride);\n\n// after: reject non-WebP / truncated streams before handing them to libwebp\nstatic bool IsWebPSignature(byte[] b)\n{\n    return b != null && b.Length >= 12\n        && b[0] == (byte)'R' && b[1] == (byte)'I' && b[2] == (byte)'F' && b[3] == (byte)'F'\n        && b[8] == (byte)'W' && b[9] == (byte)'E' && b[10] == (byte)'B' && b[11] == (byte)'P';\n}\n\nif (!IsWebPSignature(rawWebP))\n    throw new ArgumentException(\"Data is not a valid WebP stream.\");\n\nLibWebp.WebPDecodeBGRInto(ptrData, rawWebP.Length, bmpData.Scan0, outputSize, bmpData.Stride);","handlingStrategy":"validation","validationCode":"// Validate the WebP signature and buffer sizing before calling WebPDecodeBGRInto\nstatic void AssertDecodableBgr(byte[] rawWebP, IntPtr outputBuffer, int outputBufferSize, int outputStride, int width, int height)\n{\n    if (rawWebP == null || rawWebP.Length < 12)\n        throw new ArgumentException(\"WebP data is null or too short.\", nameof(rawWebP));\n    if (rawWebP[0] != (byte)'R' || rawWebP[1] != (byte)'I' || rawWebP[2] != (byte)'F' || rawWebP[3] != (byte)'F'\n        || rawWebP[8] != (byte)'W' || rawWebP[9] != (byte)'E' || rawWebP[10] != (byte)'B' || rawWebP[11] != (byte)'P')\n        throw new ArgumentException(\"Data does not have a WebP RIFF/WEBP signature.\", nameof(rawWebP));\n    if (outputBuffer == IntPtr.Zero)\n        throw new ArgumentException(\"Output buffer is null.\", nameof(outputBuffer));\n    if (outputBufferSize < outputStride * height)\n        throw new ArgumentException($\"Output buffer ({outputBufferSize}) < stride*height ({outputStride * height}).\", nameof(outputBufferSize));\n}","typeGuard":"// Runtime guard over raw byte input before decode\nstatic bool IsWebP(byte[] data) =>\n    data != null && data.Length >= 12\n    && data[0] == (byte)'R' && data[1] == (byte)'I' && data[2] == (byte)'F' && data[3] == (byte)'F'\n    && data[8] == (byte)'W' && data[9] == (byte)'E' && data[10] == (byte)'B' && data[11] == (byte)'P';","tryCatchPattern":"try\n{\n    using var bmp = new WebPWrapper().Decode(rawWebP);\n}\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"decode WebP\"))\n{\n    // Treat as an unsupported/corrupt image rather than a fatal error\n    logger.Warn(ex, \"WebP decode failed; file may be corrupt or not WebP.\");\n    ShowUnsupportedImageError(path);\n}","preventionTips":["Validate the RIFF/WEBP signature before handing bytes to libwebp.","Ship the exact bitness of libwebp.dll that matches your process (x64).","Keep the libwebp native version in lockstep with the ImageGlass.WebP wrapper's ABI constant.","Decode from a private byte[] copy so the pinned buffer cannot be mutated mid-decode.","For animated WebP, use the WebPDecoderConfig advanced path, not the single-frame BGRInto call."],"tags":["webp","image-decoding","pinvoke","libwebp","native-interop","csharp"],"backgroundTag":null,"analyzedSha":"4a3c4feceffc5a8bb5e56ba836509634aaae47a9","analyzedAt":"2026-08-13T16:58:15.523Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}