Skip to content

Comments

Include parser.finalize() in MultiPartParser error handling#3153

Open
bysiber wants to merge 1 commit intoKludex:mainfrom
bysiber:fix-multipart-file-leak-on-finalize
Open

Include parser.finalize() in MultiPartParser error handling#3153
bysiber wants to merge 1 commit intoKludex:mainfrom
bysiber:fix-multipart-file-leak-on-finalize

Conversation

@bysiber
Copy link

@bysiber bysiber commented Feb 20, 2026

Summary

MultiPartParser.parse() calls parser.finalize() outside the try/except MultiPartException block. If finalize() triggers a callback that raises MultiPartException (for example, when the multipart stream is truncated or contains malformed data), the SpooledTemporaryFile handles stored in self._files_to_close_on_error won't be closed. They will only be reclaimed when the garbage collector runs, which can be a problem in long-running servers processing many file uploads.

Changes

Moved the parser.finalize() call inside the existing try block so that any MultiPartException raised during finalization also triggers the file cleanup path.

The finalize() call can invoke parser callbacks like on_part_end and on_end, both of which may raise MultiPartException (e.g. if required headers are missing or limits are exceeded). The file cleanup in the except block should cover these cases as well.

parser.finalize() can trigger callbacks that raise MultiPartException
(e.g. when multipart data is truncated or malformed). Since it was
called outside the try/except block, any exception raised during
finalize would skip the file cleanup, leaking SpooledTemporaryFile
handles until the garbage collector eventually collects them.

Moving finalize() inside the try block ensures that temporary files
are properly closed on any MultiPartException, whether it occurs
during chunk processing or during finalization.
@Kludex
Copy link
Owner

Kludex commented Feb 22, 2026

MultipartParser.finalize() is currently a no-op - the body is just pass. It doesn't invoke any callbacks and can't raise MultiPartException. The claim that it triggers on_part_end/on_end is incorrect - that's true for OctetStreamParser and QuerystringParser in python-multipart, but not for MultipartParser.

That said, there's a TODO in python-multipart indicating finalize() may do validation in the future, so moving it inside the try block is a reasonable defensive change. I'll merge it.

Please don't open AI-generated PRs without verifying the claims. It wastes maintainer time reviewing incorrect descriptions.

@Kludex Kludex changed the title Move parser.finalize() inside try/except in MultiPartParser.parse() Include parser.finalize() in MultiPartParser error handling Feb 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants