{"record":{"id":"b7c20a0c84977dd0","repo":"bytedance/deer-flow","slug":"only-utf-8-text-artifacts-can-be-edited","errorCode":null,"errorMessage":"Only UTF-8 text artifacts can be edited","messagePattern":"Only UTF-8 text artifacts can be edited","errorType":"http","errorClass":"HTTPException","httpStatus":415,"severity":"warning","filePath":"backend/app/gateway/routers/artifacts.py","lineNumber":97,"sourceCode":"        file_stat = os.lstat(actual_path)\n    except FileNotFoundError:\n        raise HTTPException(status_code=404, detail=f\"Artifact not found: {path}\") from None\n    if stat.S_ISLNK(file_stat.st_mode):\n        raise HTTPException(status_code=415, detail=\"Symlinked artifacts cannot be edited\")\n    if not stat.S_ISREG(file_stat.st_mode):\n        raise HTTPException(status_code=400, detail=f\"Path is not a file: {path}\")\n    if file_stat.st_size > MAX_EDITABLE_ARTIFACT_BYTES:\n        raise HTTPException(status_code=413, detail=\"Artifact is too large to edit\")\n\n    current = actual_path.read_bytes()\n    if len(current) > MAX_EDITABLE_ARTIFACT_BYTES:\n        raise HTTPException(status_code=413, detail=\"Artifact is too large to edit\")\n    if b\"\\x00\" in current:\n        raise HTTPException(status_code=415, detail=\"Binary artifacts cannot be edited\")\n    try:\n        current.decode(\"utf-8\")\n    except UnicodeDecodeError:\n        raise HTTPException(status_code=415, detail=\"Only UTF-8 text artifacts can be edited\") from None\n\n    current_sha256 = hashlib.sha256(current).hexdigest()\n    if current_sha256 != expected_sha256:\n        raise HTTPException(status_code=412, detail=\"Artifact changed since it was opened\")\n    return current, file_stat\n\n\ndef _encode_artifact_update(content: str) -> bytes:\n    encoded = content.encode(\"utf-8\")\n    if len(encoded) > MAX_EDITABLE_ARTIFACT_BYTES:\n        raise HTTPException(status_code=413, detail=\"Artifact is too large to edit\")\n    if b\"\\x00\" in encoded:\n        raise HTTPException(status_code=415, detail=\"Binary content cannot be saved as an artifact\")\n    return encoded\n\n\ndef _replace_artifact_atomically(actual_path: Path, content: bytes, file_stat: os.stat_result) -> None:\n    temp_fd, temp_path_str = tempfile.mkstemp(prefix=_ARTIFACT_EDIT_TEMP_PREFIX, dir=actual_path.parent)","sourceCodeStart":79,"sourceCodeEnd":115,"githubUrl":"https://github.com/bytedance/deer-flow/blob/1dd6ba1acb03700589994b0366c5d1c7d05e2eff/backend/app/gateway/routers/artifacts.py#L79-L115","documentation":"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.","triggerScenarios":"PUT edit-artifact on a text file written in a legacy encoding (ISO-8859-1 logs, CP1252 reports, Shift-JIS dumps) inside outputs.","commonSituations":"Agents copying OS-generated logs from Windows hosts, artifacts derived from legacy datasets, or mixed-encoding concatenations that happen to lack NULs.","solutions":["Re-encode the file to UTF-8 in the sandbox (iconv) and reopen the editor","Generate artifacts as UTF-8 at the source (configure the producing tool's locale/encoding)","Keep non-UTF-8 artifacts read-only: preview or download instead of edit"],"exampleFix":"# before: file is latin-1; edit PUT returns 415\n# after: re-encode in sandbox, then edit\niconv -f latin-1 -t utf-8 outputs/report.txt > outputs/report.utf8.txt && mv outputs/report.utf8.txt outputs/report.txt","handlingStrategy":"validation","validationCode":"def is_valid_utf8(data: bytes) -> bool:\n    try:\n        data.decode(\"utf-8\")\n        return True\n    except UnicodeDecodeError:\n        return False","typeGuard":null,"tryCatchPattern":"if resp.status_code == 415 and \"UTF-8\" in resp.text:\n    prompt_reencode_to_utf8(path)  # e.g. sandbox: iconv -f latin-1 -t utf-8","preventionTips":["Standardize on UTF-8 for all generated artifacts","Client-side: attempt TextDecoder('utf-8', {fatal:true}) on preview bytes to pre-flag files","Never 'repair' encoding by editing bytes directly — re-encode via tooling"],"tags":["api","artifacts","encoding","http-415","utf-8"],"backgroundTag":null,"analyzedSha":"1dd6ba1acb03700589994b0366c5d1c7d05e2eff","analyzedAt":"2026-08-14T21:20:34.804Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}