fix: catch UnicodeDecodeError in _is_json to avoid crashing detect_filetype()#4398
Open
chuenchen309 wants to merge 2 commits into
Unstructured-IO:mainUnstructured-IO/unstructured:mainfrom
chuenchen309:fix/is-json-unicode-decode-crashchuenchen309/unstructured:fix/is-json-unicode-decode-crashCopy head branch name to clipboard
Open
fix: catch UnicodeDecodeError in _is_json to avoid crashing detect_filetype()#4398chuenchen309 wants to merge 2 commits intoUnstructured-IO:mainUnstructured-IO/unstructured:mainfrom chuenchen309:fix/is-json-unicode-decode-crashchuenchen309/unstructured:fix/is-json-unicode-decode-crashCopy head branch name to clipboard
chuenchen309 wants to merge 2 commits into
Unstructured-IO:mainUnstructured-IO/unstructured:mainfrom
chuenchen309:fix/is-json-unicode-decode-crashchuenchen309/unstructured:fix/is-json-unicode-decode-crashCopy head branch name to clipboard
Conversation
Contributor
There was a problem hiding this comment.
All reported issues were addressed across 4 files
Shadow auto-approve: would not auto-approve because issues were found.
Re-trigger cubic
Contributor
There was a problem hiding this comment.
0 issues found across 1 file (changes from recent commits).
Shadow auto-approve: would auto-approve. Minimal bug fix: catches UnicodeDecodeError in _is_json to prevent crash on non-UTF-8 bracket-prefixed text. Includes a regression test and changelog.
Re-trigger cubic
This was referenced Jul 14, 2026
…letype()
_TextFileDifferentiator._is_json calls json.load() directly on the raw
file bytes when libmagic guesses a generic text/plain MIME type and the
content starts with `[`/`{`. If the bytes aren't valid UTF-8, json.load()
raises UnicodeDecodeError (via its internal detect_encoding step), which
wasn't caught by the existing `except json.JSONDecodeError`, so it
propagated straight out of the public detect_filetype() API instead of
falling back to FileType.TXT like any other undetectable content.
Broaden the except clause to also catch UnicodeDecodeError.
Added a regression test with non-UTF-8 bytes wrapped in braces and no
file extension, confirming detect_filetype() returns FileType.TXT
instead of raising. Confirmed it fails against the pre-fix code and
passes after. Ran the full test_unstructured/file_utils/ suite (380
passed, 1 xfailed -- no regressions), ruff check/format, and bumped
__version__.py + CHANGELOG.md per the contribution checklist (note:
this may create a merge conflict with my other open PR Unstructured-IO#4397, which
also bumps to 0.25.1 from the same base -- happy to rebase whichever
merges second).
Disclosure: I used an AI coding assistant (Claude) to help identify
this bug and draft the fix. I independently reproduced the
UnicodeDecodeError crash before writing the test and ran the full
local test suite before opening this PR.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…test Addresses cubic-dev-ai review feedback: the test was named "...with_no_extension" but passed metadata_file_path="filename.pdf", so it didn't actually exercise the no-extension code path (extension would resolve to ".pdf", not ""). Drop metadata_file_path entirely — an io.BytesIO with no .name attribute makes `_FileTypeDetectionContext.extension` resolve to "" (genuinely no extension), matching what the test name claims. Behavior is unchanged either way since ".pdf" isn't in _TextFileDifferentiator's special-cased extension list, but the test now actually asserts what it says it does. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
chuenchen309
force-pushed
the
fix/is-json-unicode-decode-crash
branch
from
July 15, 2026 21:59
1840cad to
0a1fd19
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
_TextFileDifferentiator._is_jsoncallsjson.load()directly on the raw file bytes when libmagic guesses a generictext/plainMIME type and the content starts with[/{:If the bytes aren't valid UTF-8,
json.load()raisesUnicodeDecodeError(via its internaldetect_encodingstep) — a different exception type thanjson.JSONDecodeError, so it's not caught. It propagates straight out of the publicdetect_filetype()API instead of falling back toFileType.TXT, the behavior for any other content libmagic can't identify more specifically.Repro
Fix
Broaden the
exceptclause to also catchUnicodeDecodeError.Testing
test_it_does_not_crash_on_non_utf8_bracket_prefixed_text_with_no_extension, confirmingdetect_filetype()returnsFileType.TXTinstead of raising. Confirmed it fails against the pre-fix code and passes after.test_unstructured/file_utils/suite (380 passed, 1 xfailed — no regressions).ruff check/ruff format --checkclean. Bumpedunstructured/__version__.pyand added aCHANGELOG.mdentry per the contribution checklist.Note: this bumps to the same
0.25.1as my other open PR (#4397), both branched from the same base — whichever merges second will likely need a quick rebase on the version files, happy to handle that when the time comes.Disclosure: I used an AI coding assistant (Claude) to help identify this bug and draft the fix. I independently reproduced the crash before writing the regression test and ran the full local test suite before opening this PR.