Skip to content

[B03] _detect_encoding misreports valid UTF-8 CSV as non-UTF-8 when multibyte char straddles 8193-byte Range GET boundary #3

@ogawsh

Description

@ogawsh

[B03] _detect_encoding が Range GET の 8193 バイト境界で multibyte を切断し、正常な UTF-8 CSV を「UTF-8 以外」と誤検出する

再現条件

  • S3 の CSV ファイルで、先頭から 8192 バイト前後にマルチバイト UTF-8 文字(漢字など)がまたがって配置されている
  • Admin UI で /admin/analyze を実行する

観測された挙動

  • AdminBackend が以下のエラーを返す:
    CSV分析エラー: UTF-8 以外のエンコーディングが検出されました:
    testcase/B03-construction-100-files/dailyreport_20240101.csv。
    CSV は UTF-8 で保存してください。
    
  • ファイル自体は正常な UTF-8 CSV で、全体としては UTF-8 でデコードできる
  • 100 ファイル中、たまたま先頭 8193 バイト目に漢字の境界が重なったファイルだけ失敗する

原因

lambda/adminwebbackend/app.py_detect_encoding:

def _detect_encoding(bucket: str, key: str) -> None:
    resp = s3.get_object(Bucket=bucket, Key=key, Range="bytes=0-8192")
    raw = resp["Body"].read()
    try:
        raw.decode("utf-8")
    except UnicodeDecodeError:
        raise ValueError(f"UTF-8 以外のエンコーディングが検出されました: {key}。CSV は UTF-8 で保存してください。")
  • bytes=0-8192(= 8193 バイト)を取得して raw.decode("utf-8") を呼ぶ
  • UTF-8 マルチバイト文字が 8192 / 8193 バイト目をまたいで配置されていた場合、末尾が途中で切れて UnicodeDecodeError: 'utf-8' codec can't decode bytes in position N-M: unexpected end of data が発生する
  • _detect_encoding は全ての UnicodeDecodeError を「UTF-8 以外」として扱ってしまうため、正常な UTF-8 ファイルが誤検知される

実測(B03 のファイル dailyreport_20240101.csv):

UTF-8 decode FAIL: 'utf-8' codec can't decode bytes in position 8191-8192: unexpected end of data
around bytes: b'-05,S03244,\xe9\x9d\x99\xe5\xb2\xa1\xe7\x9c\x8c\xe5\xbb'
  • \xe9\x9d\x99 = (3バイト)、\xe5\xb2\xa1 = \xe7\x9c\x8c = \xe5\xbb... の 3 バイト目がちょうど 8193 バイト範囲の外
  • ファイル全体を取ってくれば utf-8 でデコードできる(8193 バイト境界の副作用でしかない)

期待される挙動

  • Range GET で取得したバイト列の末尾で 不完全なマルチバイト文字は無視して再判定する
  • 具体的な実装例:
    try:
        raw.decode("utf-8")
    except UnicodeDecodeError as e:
        # Range GET の末尾で multibyte が切れている場合は無視して末尾数バイトを落として再判定
        if e.end >= len(raw) - 3:
            truncated = raw[: max(0, e.start)]
            if not truncated:
                raise ValueError(...)
            try:
                truncated.decode("utf-8")
                return  # OK
            except UnicodeDecodeError:
                pass
        raise ValueError(f"UTF-8 以外のエンコーディングが検出されました: {key}。CSV は UTF-8 で保存してください。")
    (または codecs.iterdecode / IncrementalDecoder を使って末尾の不完全バイトを正式に無視する)

再現手順

  1. 先頭から 8KB 程度の位置に日本語(3 バイト/文字)を含む行が来るような UTF-8 CSV を用意
    • 例: report_date,site_code,site_name,...site_name静岡県 等の漢字を含め、30 〜 40 行目くらいに出現させる
  2. Admin UI から該当プレフィックスの analyze を実行
  3. ファイル全体では正常な UTF-8 にもかかわらず「UTF-8 以外」のエラーが出ることを観測

参考情報

  • 対象スタック: arn:aws:cloudformation:ap-northeast-1:411521242467:stack/devDwhAgentStack/6619ffe0-3f8b-11f1-a3dc-068ad41190bd
  • 関連ファイル: lambda/adminwebbackend/app.py _detect_encoding

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions