Repository navigation
UN-4574 [FIX] Classify files the way LLMWhisperer does so ERP xlsx exports are accepted - #2425
Open
Deepak-Kesavan wants to merge 10 commits into
Open
Deepak-Kesavan wants to merge 10 commits into
Deepak-Kesavan wants to merge 10 commits into
Conversation
…exports are accepted ERP exports whose first zip member is a leftover `[trash]/*.dat` part make libmagic report application/octet-stream for a valid xlsx. The gate only looked inside a zip when libmagic said application/zip, so these files were rejected while LLMWhisperer (which asks a second classifier) accepted them. mime_gate.classify_file_path now follows LLMWhisperer's gate step by step: whole-file libmagic, then a second look for octet-stream/zip (our zip reader standing in for Magika), then LLMWhisperer's `%PDF-` scan of the first 1024 bytes. Uploads (API deployments, Prompt Studio, FileValidator) are classified from the whole file; connector copies in the backend and workers sniff the first chunk and classify the whole file locally only when it is inconclusive.
…on a full temp dir, check size before type
Contributor
[Medium impact] The PR appears safe to merge; the previous ZIP error finding is fixed and no new blocking issue was found.
|
…s a disk fault too
chandrasekharan-zipstack
approved these changes
Nov 3, 2026
…instead of raising
… UN-4574-erp-xlsx-mime-gate
|
Contributor
Unstract test resultsPer-group results
Critical paths
|
chandrasekharan-zipstack
approved these changes
Nov 5, 2026
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.



What
Util.is_valid_file_type_from_pathin unstract-llm-whisperer), so a file LLMWhisperer would accept is no longer rejected here.FileValidatorclassify the whole file. Connector/ETL copies (backend and workers) check the first chunk and classify the whole file locally only when that check is unclear.Why
unsupported MIME type 'application/octet-stream', while LLMWhisperer extracted the same file fine (UN-4574). Re-saving in Excel "fixed" it.[trash]/0002.datpart. For that layout libmagic describes the file as "Microsoft OOXML" but reports MIMEapplication/octet-stream, notapplication/zip.application/zip, so the file stopped at octet-stream. LLMWhisperer asks Magika after an octet-stream or zip verdict, and Magika says xlsx.How
unstract/core/mime_gate.py:classify_file_path(path)copies LLMWhisperer's gate step by step:magic.from_fileon the whole file → for octet-stream/zip, a second look via our zip reader (identify_zip_container, standing in for Magika, which we deliberately don't add as a dependency) → for octet-stream/zip still, LLMWhisperer's%PDF-scan of the first 1024 bytes.classify_stream(stream, chunk_size)is for connector copies. A first chunk libmagic can name decides on its own. An unclear one (octet-stream/zip/OLE2) is copied to a local temp file and classified whole. The copy is capped at LLMWhisperer's defaultMAX_FILE_SIZE(300 MB); larger files keep the first-chunk verdict and are rejected, as LLMWhisperer would reject them anyway. The bytes are handed back for the copy, so nothing is read twice from the source.resolve_inconclusive_mime_type, which was stricter than LLMWhisperer: it needed%PDF-x.y, re-checked with libmagic, and skipped zips.backend/utils/upload_mime_type.py:detect_upload_mime_typeclassifies an upload from its temp file, or copies it to one first. A temp dir that can't be written raisesUploadSpillError(aRuntimeError), so it fails the request instead of being reported as a bad file.endpoint_v2/source.py, the worker connector copy inworkers/shared/workflow/execution/service.py,FileValidator(which now checks size before type), and Prompt Studio's upload view.Can this PR break any existing features. If yes, please list possible items. If no, please explain why. (PS: Admins do not merge the PR without this section filled)
%PDF-rule exactly: any file libmagic reports as octet-stream or zip with%PDF-in its first 1024 bytes is accepted as a PDF. That includes a zip with an uncompressed entry containing the marker. LLMWhisperer accepts these too, so they don't fail later in extraction./tmp, up to 300 MB. A legacy.doc/.xlsor an unclear binary in an ETL source now costs a local copy where it used to be judged from its first 4 MB.FileValidatornow reports an oversized file as too large before checking its type.resolve_inconclusive_mime_type, and theINCONCLUSIVE_MIME_TYPESre-exports fromworkflow_manager.endpoint_v2.enumsandshared.enums.file_types) have no users in unstract or unstract-cloud main.Database Migrations
Env Config
Relevant Docs
unstract-llm-whisperer→backend/app/util/base.pyUtil.is_valid_file_type_from_pathRelated Issues or PRs
file_converterplugin): Zipstack/unstract-cloud#1941. It depends on this PR.Dependencies Versions
Notes on Testing
backend/workflow_manager/endpoint_v2/tests/test_api_storage_mime_validation.py: 56 passed. These include an ERP-shaped xlsx (synthetic, built in the test) through the API staging loop and through the backend connector copy, and a full temp dir failing the request.workers/tests/test_mime_gate.py: 9 passed (classifier, size cap, and the worker connector copy across multiple chunks).python:3.12-slim-trixie(libmagic 5.46, the backend's base image). Before:octet-stream→ rejected. After:classify_file_pathandclassify_streamboth return xlsx, and the bytes come through unchanged.deepak-unstract-dev), before this change: the original ERP file sent to an API deployment →Rejecting file 'orig.xlsx' with unsupported MIME type 'application/octet-stream'; control workbook → Success.snapshot.1793689200): the same original ERP file → Success (passed the gate and was extracted by LLMWhisperer); control workbook → Success. The ERP file was re-sent once a minute, and the result switched from rejection to Success when the new backend pod started serving. Prompt Studio upload in the UI not yet checked.Screenshots
Checklist
I have read and understood the Contribution Guidelines.