[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 を使って末尾の不完全バイトを正式に無視する)
再現手順
- 先頭から 8KB 程度の位置に日本語(3 バイト/文字)を含む行が来るような UTF-8 CSV を用意
- 例:
report_date,site_code,site_name,... で site_name に 静岡県 等の漢字を含め、30 〜 40 行目くらいに出現させる
- Admin UI から該当プレフィックスの
analyze を実行
- ファイル全体では正常な UTF-8 にもかかわらず「UTF-8 以外」のエラーが出ることを観測
参考情報
- 対象スタック:
arn:aws:cloudformation:ap-northeast-1:411521242467:stack/devDwhAgentStack/6619ffe0-3f8b-11f1-a3dc-068ad41190bd
- 関連ファイル:
lambda/adminwebbackend/app.py _detect_encoding
[B03]
_detect_encodingが Range GET の 8193 バイト境界で multibyte を切断し、正常な UTF-8 CSV を「UTF-8 以外」と誤検出する再現条件
/admin/analyzeを実行する観測された挙動
原因
lambda/adminwebbackend/app.pyの_detect_encoding:bytes=0-8192(= 8193 バイト)を取得してraw.decode("utf-8")を呼ぶ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):\xe9\x9d\x99=静(3バイト)、\xe5\xb2\xa1=岡、\xe7\x9c\x8c=県、\xe5\xbb...の 3 バイト目がちょうど 8193 バイト範囲の外utf-8でデコードできる(8193 バイト境界の副作用でしかない)期待される挙動
codecs.iterdecode/IncrementalDecoderを使って末尾の不完全バイトを正式に無視する)再現手順
report_date,site_code,site_name,...でsite_nameに静岡県等の漢字を含め、30 〜 40 行目くらいに出現させるanalyzeを実行参考情報
arn:aws:cloudformation:ap-northeast-1:411521242467:stack/devDwhAgentStack/6619ffe0-3f8b-11f1-a3dc-068ad41190bdlambda/adminwebbackend/app.py_detect_encoding