bytedance/deer-flow · error · HTTPException
Binary content cannot be saved as an artifact
Error message
Binary content cannot be saved as an artifact
What it means
HTTP 415 from _encode_artifact_update: the incoming content string encodes to UTF-8 bytes containing a NUL byte. The save path mirrors the load-side binary check: the artifacts editor must remain text-only end to end, so binary payloads (even those smuggled inside a JSON string) are rejected before any disk write.
Source
Thrown at backend/app/gateway/routers/artifacts.py:110
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)
temp_path = Path(temp_path_str)
try:
# Preserve ownership where possible and keep replacement permissions
# scoped to the owner/group. The shared outputs directory allows a
# mounted sandbox to reach the file without making it world-writable.
if hasattr(os, "fchown"):
try:
os.fchown(temp_fd, file_stat.st_uid, file_stat.st_gid)
except OSError:
logger.debug("Could not preserve artifact ownership: %s", actual_path, exc_info=True)
# Windows has no fchmod and uses ACLs rather than POSIX mode bits.
# Keep the mkstemp permissions there; retain the existing POSIX
# behavior on platforms that expose descriptor-based chmod.View on GitHub (pinned to 1dd6ba1acb)
Solutions
- Strip or reject NUL characters in content before sending (legitimate text should never contain them)
- Use the sandbox write_file tool for anything binary — the artifacts editor is text-only by contract
- Investigate why the content contains NULs; usually a corrupted source or a misused API
Example fix
// before
await client.put(EDIT_URL, json={"path": p, "content": text_with_nuls, "sha256": sha})
// after
assert !text.includes("\u0000"); // guard client-side
await client.put(EDIT_URL, json={"path": p, "content": text, "sha256": sha}) Defensive patterns
Strategy: validation
Validate before calling
def content_is_nul_free(content: str) -> bool:
return "\x00" not in content Type guard
def is_savable_content(content: str) -> bool:
encoded = content.encode("utf-8")
return (len(encoded) <= 2 * 1024 * 1024
and b"\x00" not in encoded) Prevention
- Validate editor buffers client-side for NUL before enabling Save
- Do not use the artifact edit API as a binary file writer — route binary through sandbox tools
- Sanitize pasted content in the UI (strip control characters except \n\t\r)
When it happens
Trigger: PUT edit-artifact with a content string containing '\u0000' — programmatic clients injecting serialized/binary data through the JSON content field, or corrupted editor buffers.
Common situations: Scripts treating the edit endpoint as a generic file-write API, copy-paste of terminal control-laden output, or upstream bugs producing NULs in strings.
Related errors
- Binary artifacts cannot be edited
- Skill archives cannot be edited in the artifacts panel
- Symlinked artifacts cannot be edited
- Only UTF-8 text artifacts can be edited
- Only files in /mnt/user-data/outputs can be edited
AI-assisted analysis of bytedance/deer-flow@1dd6ba1acb (2026-08-14).
Data as JSON: /api/errors/477aa79e40162937.
Report an issue: GitHub.