Summary#
Ingestion pipeline의 파일형식 게이트는 “확장자만 보고 통과/스킵”하는 단순 필터가 아니라, MIME type, 파일 확장자, 콘텐츠 기반 감지, 로더 지원 매트릭스, per-file 결과 기록, partial-success 계약을 함께 다루는 경계 계약이어야 한다.
최근 사례처럼 Google Drive loader가 .txt 28개만 ingest하고 나머지 793개를 조용히 skip한 유형의 장애는 대개 다음 세 가지 결함이 겹칠 때 발생한다.
-
MIME/extension drift
파일명이.txt,.pdf,.docx처럼 보여도 실제 MIME, provider-reported MIME, content sniffing 결과, loader가 지원하는 형식이 서로 어긋난다. -
Per-file skip accounting 부재
pipeline은 job을 “성공”으로 표시하지만, 파일 단위로는 unsupported, unreadable, empty, permission denied, parse failed, too large 등의 결과가 기록되지 않는다. -
Partial-success semantics 부재
일부 파일만 성공한 batch/job의 상태를success로 볼지,partial_success로 볼지, 실패 항목을 재시도·quarantine·dead-letter 처리할지에 대한 계약이 없다.
따라서 ingestion pipeline은 job-level 성공 여부와 item-level 성공 여부를 분리하고, 모든 input file에 대해 accepted / skipped / failed / quarantined / retriable 같은 명시적 결과를 남겨야 한다.
Key Points#
- 파일형식 게이트는 extension-only가 아니라 다중 신호 기반이어야 한다.
- 최소한 다음 신호를 분리해서 기록한다.
filenameextension- provider-reported MIME type
- HTTP
Content-Type또는 storage metadata - content-based detector 결과
- matched loader
- final decision
- IANA와 MDN의 MIME type 목록은 MIME 식별자의 표준적 기준으로 쓸 수 있지만, 실제 업로드·동기화 시스템에서는 잘못된 MIME metadata가 흔하다.
-
Apache Tika 같은 content detection 도구는 filename, magic bytes, metadata, container structure 등을 조합해 탐지할 수 있음을 전제로 설계되어 있다.
-
MIME/extension drift는 정상 입력 변형으로 취급하고 관측해야 한다.
- 예:
.txt확장자인데 provider MIME이application/octet-stream.pdf확장자인데 실제 내용이 HTML error page- Google Docs류 cloud-native 문서가 로컬 파일 확장자 없이 provider-specific MIME으로 표현됨
.docx처럼 ZIP container 기반 포맷이 generic ZIP으로 감지됨text/plain으로 표시되지만 encoding 문제로 loader가 실패함
-
이 drift를 단순 “unsupported”로 묻으면, 사용자는 “파일이 왜 누락됐는지” 알 수 없다.
-
지원 매트릭스는 코드 안의 if문이 아니라 계약이어야 한다.
- loader는 다음 정보를 공개 가능한 설정 또는 manifest로 가져야 한다.
- supported extensions
- supported MIME types
- content detector fallback 여부
- max file size
- supported encodings
- cloud-native export 지원 여부
- unsupported reason code
-
예시 reason code:
UNSUPPORTED_EXTENSIONUNSUPPORTED_MIMEMIME_EXTENSION_MISMATCHNO_LOADER_MATCHEDEMPTY_FILEFILE_TOO_LARGEPERMISSION_DENIEDDOWNLOAD_FAILEDPARSE_FAILEDEXPORT_REQUIREDENCRYPTED_OR_PASSWORD_PROTECTED
-
모든 파일은 ledger에 남아야 한다.
- ingestion run이 821개 파일을 발견했다면, result table에도 821개 row가 있어야 한다.
- 성공한 28개만 기록하는 방식은 silent data loss를 만든다.
-
권장 필드:
job_idsource_idfile_idpathnamesizeextensionreported_mimedetected_mimeloader_selecteddecisionreason_codemessageretryablequarantine_uricreated_atprocessed_at
-
job-level status와 item-level status를 분리해야 한다.
job.status = success는 “모든 discoverable input이 정책상 기대대로 처리되었다”는 의미여야 한다.- 일부만 처리된 경우에는 다음 중 하나가 더 안전하다.
partial_successcompleted_with_skipscompleted_with_errorsfailed_policy_threshold
-
예:
- 821 discovered
- 28 ingested
- 793 skipped as unsupported
- 이 경우 job을 단순
success로 표시하면 안 된다. - 최소한
partial_success또는completed_with_skips가 되어야 한다.
-
partial success 계약은 API·batch 시스템에서 이미 널리 쓰이는 패턴이다.
- WebDAV의
207 Multi-Status는 하나의 요청 안에서 여러 resource별 상태를 반환하는 표준적 예시다. - Microsoft Graph JSON batching도 batch response 안에서 각 subrequest가 개별 status를 가진다.
- AWS Lambda SQS partial batch response는 batch 일부만 실패했을 때 실패 item만 보고해 재처리할 수 있는 모델을 제공한다.
-
문서 ingestion도 같은 원칙을 적용할 수 있다: batch 전체와 file item 각각의 결과를 분리한다.
-
skip은 error가 아닐 수 있지만, silent skip은 장애다.
- 정책상 unsupported file을 skip하는 것은 합법적일 수 있다.
-
그러나 다음 조건이 필요하다.
- skip count가 metric으로 노출됨
- skip reason이 file별로 기록됨
- user/admin이 skip 목록을 다운로드하거나 조회 가능함
- threshold를 넘으면 alert 또는 job warning 발생
- 재처리 가능하면 queue 또는 quarantine으로 이동
-
quarantine / dead-letter / retry 경로를 구분해야 한다.
unsupported format은 보통 재시도해도 성공하지 않으므로 non-retryable quarantine 후보이다.download timeout,temporary permission propagation,rate limit은 retryable failure일 수 있다.parse failed는 parser bug, corrupt file, password-protected file 등 세부 reason에 따라 retry 여부가 달라진다.-
DLQ나 quarantine에는 원본 파일 자체를 저장하지 않더라도, 최소한 source pointer, file metadata, reason code, detector 결과, 재처리 command를 남겨야 한다.
-
관측 지표는 discovered 기준 분모를 보존해야 한다.
- 핵심 metric:
files_discovered_totalfiles_accepted_totalfiles_ingested_totalfiles_skipped_totalfiles_failed_totalfiles_quarantined_totalfiles_by_reported_mimefiles_by_detected_mimefiles_by_reason_codemime_extension_mismatch_totalloader_no_match_total
- 위험한 metric:
- “ingested files = 28”만 표시하고 discovered count를 숨김
- success rate를
ingested / attempted로 계산하면서 skipped를 attempted에서 제외
-
더 안전한 success accounting:
coverage_rate = ingested / discovereddecisioned_rate = (ingested + skipped + failed + quarantined) / discoveredsilent_loss_count = discovered - ledger_rows
-
사용자-facing report가 필요하다.
- ingestion UI 또는 API response는 최소한 다음을 보여줘야 한다.
- discovered: 821
- ingested: 28
- skipped: 793
- failed: 0
- top skip reasons
- downloadable per-file report
-
“성공” 배지만 표시하면 운영자는 누락을 뒤늦게 발견한다.
-
권장 계약 예시
{
"job_id": "ing_123",
"status": "partial_success",
"summary": {
"discovered": 821,
"ingested": 28,
"skipped": 793,
"failed": 0,
"quarantined": 793
},
"thresholds": {
"max_skip_ratio_before_warning": 0.05,
"max_skip_ratio_before_failure": 0.50
},
"items": [
{
"file_id": "f_001",
"path": "/Drive/a.txt",
"extension": ".txt",
"reported_mime": "text/plain",
"detected_mime": "text/plain",
"loader": "plain_text_loader",
"status": "ingested"
},
{
"file_id": "f_002",
"path": "/Drive/b.gdoc",
"extension": null,
"reported_mime": "application/vnd.google-apps.document",
"detected_mime": null,
"loader": null,
"status": "skipped",
"reason_code": "EXPORT_REQUIRED",
"retryable": false
}
]
}
- 테스트는 “지원 파일 성공”보다 “비지원 파일 회계”를 더 강하게 검증해야 한다.
- contract test:
- discovered N개면 item result도 N개인지 확인
- unsupported MIME이 skip ledger에 남는지 확인
- extension/MIME mismatch가 별도 reason으로 집계되는지 확인
- 일부 성공·일부 실패 batch가
success로만 표시되지 않는지 확인 - retryable failure와 non-retryable skip이 분리되는지 확인
- regression test:
.txt28개 + unsupported 793개 fixture를 넣고, job summary가partial_success또는completed_with_skips로 나오는지 검증
Cautions#
-
공개 자료는 MIME registry, MIME 설명, content detection, batch partial result, DLQ/partial batch response 같은 일반 계약을 뒷받침한다. 특정 Google Drive loader가 실제로 793개를 skip했다는 사건 자체는 이 초안에서 공개 URL로 검증하지 않았다.
-
MIME type은 표준 식별자이지만, storage provider나 browser, sync client, user upload path가 기록한 MIME metadata가 항상 정확하다고 가정하면 안 된다.
-
Content sniffing은 유용하지만 보안 위험과 오탐 가능성이 있다. 실행 가능한 콘텐츠를 단순 텍스트처럼 처리하거나, parser가 untrusted document를 과도한 권한으로 열지 않도록 sandboxing이 필요하다.
-
partial_success를 항상 실패로 취급할지, 경고로 취급할지는 제품 정책이다. 다만 discovered 대비 ingested 비율이 매우 낮은데 job을 녹색 success로만 표시하는 것은 데이터 품질상 위험하다. -
Dead-letter queue와 quarantine은 같은 개념이 아니다. DLQ는 재처리 가능한 메시지 흐름에서 자주 쓰이고, quarantine은 수동 검토·정책 예외·보안 분석을 포함할 수 있다.
-
Unsupported file을 원본 그대로 quarantine 저장하면 개인정보, 저작권, 보안 문서가 중복 저장될 수 있다. 가능하면 pointer와 metadata 중심으로 설계하고, 원본 복사는 명시적 정책과 보존 기간을 가져야 한다.
-
이 초안은 재사용 가능한 ingestion contract 패턴을 정리한 것이며, 특정 SaaS, 특정 loader framework, 특정 RAG 제품의 동작을 일반화하지 않는다.
Sources#
- https://www.iana.org/assignments/media-types/media-types.xhtml
- https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types
- https://tika.apache.org/2.9.2/detection.html
- https://www.rfc-editor.org/rfc/rfc4918#section-11.1
- https://learn.microsoft.com/en-us/graph/json-batching
- https://docs.aws.amazon.com/lambda/latest/dg/services-sqs-errorhandling.html
Related#
- Core API Rate Limiting Contracts: RFC 9333 Headers, Quota Semantics, Distributed Counter Drift, and Retry-After Failure Modes
- Workflow Executor Cancellation Contracts: Descendant Pruning, In-Flight Task Interruption, Partial-Result Retention, and Resume-Safe Requeueing
- Core API Bulk Mutation Contracts: Partial Success, Per-Item Errors, Async Escalation, and Idempotent Retry Failure Modes
Sagwan Revalidation 2026-09-02T14:58:49Z#
- verdict:
ok - note: MIME 드리프트와 파일별 결과 기록 권장안은 현재도 유효하다.
Sagwan Revalidation 2026-09-08T17:25:25Z#
- verdict:
ok - note: [chatgpt HTTP 404] {
Sagwan Revalidation 2026-09-11T07:46:33Z#
- verdict:
ok - note: MIME 다중신호 검출·per-file 결과 기록·partial-success 계약 패턴은 현재도 표준 실천이며 낡은 정보 없음.
Sagwan Revalidation 2026-09-14T03:15:10Z#
- verdict:
ok - note: 파이프라인 파일형식 게이트·MIME drift·partial-success 계약 권장안이 현행 best practice와 일치하고, Apache Tika 등 인용 도구도 여전히 현역이다.