Skip to content

Improve WebP encoder error handling - #10039

Open
akx wants to merge 1 commit into
python-pillow:mainfrom
akx:webp-errors
Open

akx wants to merge 1 commit into
python-pillow:mainfrom
akx:webp-errors

Conversation

@akx

@akx akx commented Sep 22, 2026

Copy link
Copy Markdown
Contributor

Follows up on #5471 and #9993.

Instead of reporting just "error 6", this PR adds human-readable error messages for the WebP encoder errors. The error messages are based on the WebP header.

The memory-hungry (675 MB allocated for test image) test_write_encoding_error_message test case (that tested "partition is bigger than 512k") is no longer necessary, since test_write_encoding_error_bad_dimension covers the same code path.

That error message is improved too, though:

>>> from PIL import Image
>>> Image.new("RGB", (15000, 15000)).save("foo.webp", method=0)
[...]
ValueError: encoding error 6: partition #0 is bigger than 512K

Follows up on python-pillow#5471 and python-pillow#9993.

Instead of reporting just "error 6", this PR adds human-readable error messages
for the WebP encoder errors. The error messages are based on the WebP header.

The memory-hungry `test_write_encoding_error_message` test case (that tested
"partition is bigger than 512k") is no longer necessary, since
`test_write_encoding_error_bad_dimension` covers the same code path.
Comment thread src/_webp.c
#define WEBP_STR_HELPER(x) #x
#define WEBP_STR(x) WEBP_STR_HELPER(x)

static const char *const kEncoderErrorMessages[VP8_ENC_ERROR_LAST] = {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@radarhere radarhere added the WebP label Sep 22, 2026
@radarhere

Copy link
Copy Markdown
Member

I'm reluctant to remove the test, since it is guarding against regression for the specific case of #5461.

Comment thread src/_webp.c
"out of memory re-allocating byte buffer",
"NULL parameter passed to function",
"configuration is invalid",
"image size exceeds WebP limit of " WEBP_STR(WEBP_MAX_DIMENSION) " pixels",

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the story with WEBP_STR and WEBP_STR_HELPER? Why do they need to be defined separately, and why are there two of them?

@akx akx Sep 22, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's just C preprocessor expansion rules and standard procedure:

a.c

#define WEBP_MAX_DIMENSION 123

// Doesn't work like we want
#define WEBP_STR_1(x) #x
WEBP_STR_1(WEBP_MAX_DIMENSION)

// Works like we want
#define WEBP_STR_HELPER(x) #x
#define WEBP_STR_2(x) WEBP_STR_HELPER(x)
WEBP_STR_2(WEBP_MAX_DIMENSION)

Preprocessing:

$ gcc -E a.c
# 1 "a.c"
# 1 "<built-in>" 1
# 1 "<built-in>" 3
# 466 "<built-in>" 3
# 1 "<command line>" 1
# 1 "<built-in>" 2
# 1 "a.c" 2



"WEBP_MAX_DIMENSION"




"123"

This shows up in Pillow e.g. here (#4700):

Pillow/src/_imaging.c

Lines 4372 to 4374 in 4b03987

#define tostr1(a) #a
#define tostr(a) tostr1(a)
PyObject *v = PyUnicode_FromString(tostr(LIBJPEG_TURBO_VERSION));

Comment thread src/_webp.c
PyErr_Format(PyExc_ValueError, "encoding error %d%s", error_code, message);
free(output);
return NULL;
return HandleEncoderError(pic.error_code);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does HandleEncoderError need to be a separate function?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It doesn't, but it follows the form of HandleMuxError, above. Would you prefer it inlined?

@akx

akx commented Sep 22, 2026

Copy link
Copy Markdown
Contributor Author

I'm reluctant to remove the test, since it is guarding against regression for the specific case of #5461.

AISI, the issue there is the WebP encoder not having reported even an error code? As noted in the PR description, with this PR that user will get "encoding error 6: partition #0 is bigger than 512K" (instead of "encoding error 6" as of #5471).

Since the remaining test covers the entire error handling code, IMO this PR covers that case too but without having to allocate a large image the WebP encoder can't fit in partition #0 (whatever that means 😅).

I'm having a hard time seeing the way this'd regress. Someone would need to explicitly change the error handling in the WebP encoder for worse?

EDIT: #9936 will enable the knob to tweak partition_limit, as noted in that issue 😄

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants