Skip to content

fix(evals): open data file with utf-8-sig to support BOM-encoded jsonl inputs#4202

Open
Mukller wants to merge 2 commits into
microsoft:mainfrom
Mukller:fix/eval-utf8-sig-encoding
Open

fix(evals): open data file with utf-8-sig to support BOM-encoded jsonl inputs#4202
Mukller wants to merge 2 commits into
microsoft:mainfrom
Mukller:fix/eval-utf8-sig-encoding

Conversation

@Mukller

@Mukller Mukller commented Jul 15, 2026

Copy link
Copy Markdown

Fixes

Fixes #3670.

_validate_and_load_data passes the raw data path string to pd.read_json(data, lines=True).
pd.read_json uses the system default encoding when opening files, which is UTF-8 on most
systems but does not strip a UTF-8 BOM (\xef\xbb\xbf). A JSONL file written with
utf-8-sig encoding (BOM-prefixed UTF-8) causes pd.read_json to emit ValueError: Expected object or value because the BOM sits in front of the first {.

Fix

Open the data file explicitly with encoding="utf-8-sig" and pass the resulting file object
to pd.read_json. Python's utf-8-sig codec:

  • Strips the BOM when present (handles utf-8-sig clients).
  • Reads plain UTF-8 files unchanged (backwards-compatible).
# Before:
initial_data_df = pd.read_json(data, lines=True)

# After:
with open(data, encoding="utf-8-sig") as _f:
    initial_data_df = pd.read_json(_f, lines=True)

The error message and the surrounding try/except are unchanged; the only difference is
how the file is opened.

Reproduction

import json, pathlib, tempfile
from promptflow.evals.evaluate import evaluate

# Create a BOM-prefixed JSONL file
with tempfile.NamedTemporaryFile(mode='w', encoding='utf-8-sig', suffix='.jsonl', delete=False) as f:
    json.dump({"question": "What is 2+2?"}, f)
    path = f.name

# Before fix: ValueError: Failed to load data from …
# After fix:  loads successfully

Closes #3670.

@Mukller Mukller left a comment

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Self-Review

Root Cause

pd.read_json(data, lines=True) opens the file using the default system encoding.
On all common systems that default is UTF-8, which does not strip a Byte Order Mark.
A BOM (\xef\xbb\xbf) at the start of the file makes the JSON parser see the BOM
as the first character of the first token, which is not valid JSON → ValueError.

utf-8-sig is a Python built-in codec that reads UTF-8 BOM as a signal to skip the
BOM, while reading plain UTF-8 identically. It is the standard fix for BOM-related
encoding issues.

Correctness

Input encoding Before After
UTF-8 (no BOM) OK OK (unchanged)
UTF-8 with BOM ValueError OK (BOM stripped)
Other encodings ValueError ValueError (same)

The fix is strictly more permissive: existing UTF-8 files are unaffected, and BOM-prefixed
files now load correctly.

Scope

Two lines changed in _validate_and_load_data. The error handling, the return value, and
all callers are unchanged.

@Mukller
Mukller requested a review from a team as a code owner July 15, 2026 16:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG]prompt flow eval only supports UTF8 encoding

1 participant