d2phap/ImageGlass · error · InvalidOperationException
Can not decode WebP
Error message
Can not decode WebP
What it means
Thrown by WebPDecodeBGRAInto in ImageGlass.WebP when the native libwebp function returns NULL. The native API returns the output_buffer pointer on success and NULL on failure; the C# wrapper marshals it as Nullable<IntPtr> (WebPDecodeBGRAInto_x64) and converts null into this InvalidOperationException. This is the decode path used by WebPWrapper.Decode for 32-bpp ARGB (alpha-bearing) WebP images. Note the message says 'Can not' (two words), inconsistent with the BGR path which uses 'Cannot'.
Source
Thrown at v9/Components/ImageGlass.WebP/libwebp.cs:223
if (WebPDecodeBGRInto_x64(data, (UIntPtr)data_size, output_buffer, output_buffer_size, output_stride) == null)
throw new InvalidOperationException("Cannot decode WebP");
}
[DllImport("libwebp.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPDecodeBGRInto")]
private static extern IntPtr? WebPDecodeBGRInto_x64([InAttribute()] IntPtr data, UIntPtr data_size, IntPtr output_buffer, int output_buffer_size, int output_stride);
/// <summary>Decode WEBP image pointed to by *data and returns BGRA samples into a preallocated buffer</summary>
/// <param name="data">Pointer to WebP image data</param>
/// <param name="data_size">This is the size of the memory block pointed to by data containing the image data</param>
/// <param name="output_buffer">Pointer to decoded WebP image</param>
/// <param name="output_buffer_size">Size of allocated buffer</param>
/// <param name="output_stride">Specifies the distance between scan lines</param>
internal static void WebPDecodeBGRAInto(IntPtr data, int data_size, IntPtr output_buffer, int output_buffer_size, int output_stride)
{
if (WebPDecodeBGRAInto_x64(data, (UIntPtr)data_size, output_buffer, output_buffer_size, output_stride) == null)
throw new InvalidOperationException("Can not decode WebP");
}
[DllImport("libwebp.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "WebPDecodeBGRAInto")]
private static extern IntPtr? WebPDecodeBGRAInto_x64([InAttribute()] IntPtr data, UIntPtr data_size, IntPtr output_buffer, int output_buffer_size, int output_stride);
/// <summary>Decode WEBP image pointed to by *data and returns ARGB samples into a preallocated buffer</summary>
/// <param name="data">Pointer to WebP image data</param>
/// <param name="data_size">This is the size of the memory block pointed to by data containing the image data</param>
/// <param name="output_buffer">Pointer to decoded WebP image</param>
/// <param name="output_buffer_size">Size of allocated buffer</param>
/// <param name="output_stride">Specifies the distance between scan lines</param>
internal static void WebPDecodeARGBInto(IntPtr data, int data_size, IntPtr output_buffer, int output_buffer_size, int output_stride)
{
if (WebPDecodeARGBInto_x64(data, (UIntPtr)data_size, output_buffer, output_buffer_size, output_stride) == null)
throw new InvalidOperationException("Can not decode WebP");
}View on GitHub (pinned to 4a3c4fecef)
Solutions
- Validate the WebP RIFF/WEBP signature and that the byte length is plausible for the declared dimensions before decoding.
- Ensure libwebp.dll matches the process architecture (x64) and the ABI version the wrapper was compiled against.
- Verify output_buffer_size >= stride * height and output_stride == BitmapData.Stride for the 32bpp bitmap.
- Decode from a private copy of the byte buffer so no other thread can mutate it while pinned.
- Route animated or feature-rich streams through the WebPDecoderConfig advanced decode path rather than BGRAInto.
Example fix
// before
if (bmp.PixelFormat == PixelFormat.Format24bppRgb)
LibWebp.WebPDecodeBGRInto(ptrData, rawWebP.Length, bmpData.Scan0, outputSize, bmpData.Stride);
else
LibWebp.WebPDecodeBGRAInto(ptrData, rawWebP.Length, bmpData.Scan0, outputSize, bmpData.Stride);
// after: guard the input, then decode
if (rawWebP == null || rawWebP.Length < 12
|| rawWebP[0] != (byte)'R' || rawWebP[8] != (byte)'W')
{
throw new ArgumentException("Not a WebP stream.");
}
if (bmp.PixelFormat == PixelFormat.Format24bppRgb)
LibWebp.WebPDecodeBGRInto(ptrData, rawWebP.Length, bmpData.Scan0, outputSize, bmpData.Stride);
else
LibWebp.WebPDecodeBGRAInto(ptrData, rawWebP.Length, bmpData.Scan0, outputSize, bmpData.Stride); Defensive patterns
Strategy: validation
Validate before calling
// Validate WebP signature + 32bpp ARGB buffer sizing before WebPDecodeBGRAInto
static void AssertDecodableBgra(byte[] rawWebP, IntPtr outputBuffer, int outputBufferSize, int outputStride, int width, int height)
{
if (rawWebP == null || rawWebP.Length < 12
|| rawWebP[0] != (byte)'R' || rawWebP[3] != (byte)'F'
|| rawWebP[8] != (byte)'W' || rawWebP[11] != (byte)'P')
throw new ArgumentException("Not a valid WebP stream.", nameof(rawWebP));
if (outputBuffer == IntPtr.Zero)
throw new ArgumentException("Output buffer is null.", nameof(outputBuffer));
if (outputBufferSize < outputStride * height)
throw new ArgumentException("Output buffer too small for 32bpp decode.", nameof(outputBufferSize));
} Type guard
static bool IsWebP(byte[] data) =>
data != null && data.Length >= 12
&& data[0] == (byte)'R' && data[1] == (byte)'I' && data[2] == (byte)'F' && data[3] == (byte)'F'
&& data[8] == (byte)'W' && data[9] == (byte)'E' && data[10] == (byte)'B' && data[11] == (byte)'P'; Try / catch
try
{
using var bmp = new WebPWrapper().Decode(rawWebP);
}
catch (InvalidOperationException ex) when (ex.Message.Contains("decode WebP"))
{
logger.Warn(ex, "Alpha WebP decode failed; stream may be corrupt or truncated.");
ShowUnsupportedImageError(path);
} Prevention
- Check the RIFF/WEBP header and a plausible length before decoding.
- Match libwebp.dll bitness and ABI version to the wrapper.
- Size the 32bpp output buffer to at least stride * height and use the real BitmapData.Stride.
- Decode from a buffer no other thread can write to.
- Route animated WebP through the advanced decode path, not BGRAInto.
When it happens
Trigger: Calling WebPWrapper.Decode (or LibWebp.WebPDecodeBGRAInto directly) for an alpha WebP whose bytes are truncated, corrupted, or not WebP; a data_size that does not match the real buffer length; an output_buffer too small for stride*height; an output_stride that disagrees with the locked BitmapData.Stride; or a libwebp.dll with an incompatible ABI version.
Common situations: A partially downloaded .webp is truncated mid-stream; a PNG/JPEG renamed to .webp is fed to the decoder; rawWebP is edited on another thread while pinned for decode; the deployed libwebp.dll has the wrong bitness or a newer/older ABI than the wrapper; or an animated WebP is decoded through the single-frame BGRAInto path instead of the animation decoder.
Related errors
- Cannot decode WebP
- WebPInitDecoderConfig failed. Wrong version?
- Failed WebPGetFeatures with error {result}
- Crop options exceeded WebP image dimensions
- Failed WebPDecode with error {result}
AI-assisted analysis of d2phap/ImageGlass@4a3c4fecef (2026-08-13).
Data as JSON: /api/errors/0a11dbba25737976.
Report an issue: GitHub.