bytedance/deer-flow · warning · HTTPException

Only UTF-8 text artifacts can be edited

Error message

Only UTF-8 text artifacts can be edited

What it means

HTTP 415 from _load_editable_artifact: current.decode('utf-8') raised UnicodeDecodeError — the file has no NUL bytes (so it passed the binary heuristic) but is not valid UTF-8, e.g. Latin-1/Shift-JIS/CP1252 text. Editing requires an exact byte-preserving round trip, which non-UTF-8 encodings cannot guarantee through the string-based API.

Source

Thrown at backend/app/gateway/routers/artifacts.py:97

        file_stat = os.lstat(actual_path)
    except FileNotFoundError:
        raise HTTPException(status_code=404, detail=f"Artifact not found: {path}") from None
    if stat.S_ISLNK(file_stat.st_mode):
        raise HTTPException(status_code=415, detail="Symlinked artifacts cannot be edited")
    if not stat.S_ISREG(file_stat.st_mode):
        raise HTTPException(status_code=400, detail=f"Path is not a file: {path}")
    if file_stat.st_size > MAX_EDITABLE_ARTIFACT_BYTES:
        raise HTTPException(status_code=413, detail="Artifact is too large to edit")

    current = actual_path.read_bytes()
    if len(current) > MAX_EDITABLE_ARTIFACT_BYTES:
        raise HTTPException(status_code=413, detail="Artifact is too large to edit")
    if b"\x00" in current:
        raise HTTPException(status_code=415, detail="Binary artifacts cannot be edited")
    try:
        current.decode("utf-8")
    except UnicodeDecodeError:
        raise HTTPException(status_code=415, detail="Only UTF-8 text artifacts can be edited") from None

    current_sha256 = hashlib.sha256(current).hexdigest()
    if current_sha256 != expected_sha256:
        raise HTTPException(status_code=412, detail="Artifact changed since it was opened")
    return current, file_stat


def _encode_artifact_update(content: str) -> bytes:
    encoded = content.encode("utf-8")
    if len(encoded) > MAX_EDITABLE_ARTIFACT_BYTES:
        raise HTTPException(status_code=413, detail="Artifact is too large to edit")
    if b"\x00" in encoded:
        raise HTTPException(status_code=415, detail="Binary content cannot be saved as an artifact")
    return encoded


def _replace_artifact_atomically(actual_path: Path, content: bytes, file_stat: os.stat_result) -> None:
    temp_fd, temp_path_str = tempfile.mkstemp(prefix=_ARTIFACT_EDIT_TEMP_PREFIX, dir=actual_path.parent)

View on GitHub (pinned to 1dd6ba1acb)

Solutions

  1. Re-encode the file to UTF-8 in the sandbox (iconv) and reopen the editor
  2. Generate artifacts as UTF-8 at the source (configure the producing tool's locale/encoding)
  3. Keep non-UTF-8 artifacts read-only: preview or download instead of edit

Example fix

# before: file is latin-1; edit PUT returns 415
# after: re-encode in sandbox, then edit
iconv -f latin-1 -t utf-8 outputs/report.txt > outputs/report.utf8.txt && mv outputs/report.utf8.txt outputs/report.txt
Defensive patterns

Strategy: validation

Validate before calling

def is_valid_utf8(data: bytes) -> bool:
    try:
        data.decode("utf-8")
        return True
    except UnicodeDecodeError:
        return False

Try / catch

if resp.status_code == 415 and "UTF-8" in resp.text:
    prompt_reencode_to_utf8(path)  # e.g. sandbox: iconv -f latin-1 -t utf-8

Prevention

When it happens

Trigger: PUT edit-artifact on a text file written in a legacy encoding (ISO-8859-1 logs, CP1252 reports, Shift-JIS dumps) inside outputs.

Common situations: Agents copying OS-generated logs from Windows hosts, artifacts derived from legacy datasets, or mixed-encoding concatenations that happen to lack NULs.

Related errors


AI-assisted analysis of bytedance/deer-flow@1dd6ba1acb (2026-08-14). Data as JSON: /api/errors/b7c20a0c84977dd0. Report an issue: GitHub.