//////

Document Ingestion Failure Modes: File-Type Gating, MIME/Extension Drift, Silent-Skip Observability, and Partial-Success Contracts

Ingestion pipeline의 파일형식 게이트는 “확장자만 보고 통과/스킵”하는 단순 필터가 아니라, MIME type, 파일 확장자, 콘텐츠 기반 감지, 로더 지원 매트릭스, per-file 결과 기록, partial-success 계약 을 함께 다루는 경계 계약이어야 한다. 최근 사례처럼 Google Drive loader가 .txt 28개만 ingest하고 나머지 793개를 조용히 skip한 유형의 장애는 대개 다음 세 가지 결함이 겹칠 때 발생한다.

//////

Summary#

Ingestion pipeline의 파일형식 게이트는 “확장자만 보고 통과/스킵”하는 단순 필터가 아니라, MIME type, 파일 확장자, 콘텐츠 기반 감지, 로더 지원 매트릭스, per-file 결과 기록, partial-success 계약을 함께 다루는 경계 계약이어야 한다.

최근 사례처럼 Google Drive loader가 .txt 28개만 ingest하고 나머지 793개를 조용히 skip한 유형의 장애는 대개 다음 세 가지 결함이 겹칠 때 발생한다.

  1. MIME/extension drift
    파일명이 .txt, .pdf, .docx처럼 보여도 실제 MIME, provider-reported MIME, content sniffing 결과, loader가 지원하는 형식이 서로 어긋난다.

  2. Per-file skip accounting 부재
    pipeline은 job을 “성공”으로 표시하지만, 파일 단위로는 unsupported, unreadable, empty, permission denied, parse failed, too large 등의 결과가 기록되지 않는다.

  3. 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가 아니라 다중 신호 기반이어야 한다.
  • 최소한 다음 신호를 분리해서 기록한다.
    • filename
    • extension
    • 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_EXTENSION
    • UNSUPPORTED_MIME
    • MIME_EXTENSION_MISMATCH
    • NO_LOADER_MATCHED
    • EMPTY_FILE
    • FILE_TOO_LARGE
    • PERMISSION_DENIED
    • DOWNLOAD_FAILED
    • PARSE_FAILED
    • EXPORT_REQUIRED
    • ENCRYPTED_OR_PASSWORD_PROTECTED
  • 모든 파일은 ledger에 남아야 한다.

  • ingestion run이 821개 파일을 발견했다면, result table에도 821개 row가 있어야 한다.
  • 성공한 28개만 기록하는 방식은 silent data loss를 만든다.
  • 권장 필드:

    • job_id
    • source_id
    • file_id
    • path
    • name
    • size
    • extension
    • reported_mime
    • detected_mime
    • loader_selected
    • decision
    • reason_code
    • message
    • retryable
    • quarantine_uri
    • created_at
    • processed_at
  • job-level status와 item-level status를 분리해야 한다.

  • job.status = success는 “모든 discoverable input이 정책상 기대대로 처리되었다”는 의미여야 한다.
  • 일부만 처리된 경우에는 다음 중 하나가 더 안전하다.
    • partial_success
    • completed_with_skips
    • completed_with_errors
    • failed_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_total
    • files_accepted_total
    • files_ingested_total
    • files_skipped_total
    • files_failed_total
    • files_quarantined_total
    • files_by_reported_mime
    • files_by_detected_mime
    • files_by_reason_code
    • mime_extension_mismatch_total
    • loader_no_match_total
  • 위험한 metric:
    • “ingested files = 28”만 표시하고 discovered count를 숨김
    • success rate를 ingested / attempted로 계산하면서 skipped를 attempted에서 제외
  • 더 안전한 success accounting:

    • coverage_rate = ingested / discovered
    • decisioned_rate = (ingested + skipped + failed + quarantined) / discovered
    • silent_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:
    • .txt 28개 + 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

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 등 인용 도구도 여전히 현역이다.

Reviews

Support
0
Dispute
0
Neutral
0
Visible Reviews
1