bytedance/deer-flow · error · HTTPException
Path is not a file: {path}
Error message
Path is not a file: {path} What it means
HTTP 400 from _load_editable_artifact: lstat succeeded but the mode is not S_ISREG (and not a symlink, which 415 catches first). The path exists but is a directory, FIFO, device, or socket — the text editor only operates on regular files.
Source
Thrown at backend/app/gateway/routers/artifacts.py:85
def _normalize_editable_artifact_path(path: str) -> str:
stripped = path.lstrip("/")
if not stripped.startswith(_EDITABLE_OUTPUTS_PREFIX):
raise HTTPException(status_code=400, detail="Only files in /mnt/user-data/outputs can be edited")
if ".skill/" in stripped or stripped.endswith(".skill"):
raise HTTPException(status_code=415, detail="Skill archives cannot be edited in the artifacts panel")
return f"/{stripped}"
def _load_editable_artifact(actual_path: Path, path: str, expected_sha256: str) -> tuple[bytes, os.stat_result]:
try:
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
View on GitHub (pinned to 1dd6ba1acb)
Solutions
- Fix the client path to point at a concrete file inside the directory
- Filter directories out of anything the user can click Edit on
- If a special file is intentional, it is not editable — remove it from the editor surface
Example fix
// before
await client.put(EDIT_URL, json={"path": "mnt/user-data/outputs/report", ...})
// after
await client.put(EDIT_URL, json={"path": "mnt/user-data/outputs/report/summary.md", ...}) Defensive patterns
Strategy: validation
Validate before calling
import os, stat
def is_regular_file(path: str) -> bool:
try:
return stat.S_ISREG(os.lstat(path).st_mode)
except OSError:
return False Type guard
import os, stat
def is_editable_target(path: str) -> bool:
"""Regular non-symlink file under outputs."""
try:
st = os.lstat(path)
except OSError:
return False
return stat.S_ISREG(st.st_mode) and path.lstrip("/").startswith("mnt/user-data/outputs/") Prevention
- Never offer Edit actions on directory entries in artifact trees
- Validate that constructed paths end in a filename, not a directory
- Remember order: symlink → 415, non-regular → 400, so client checks should mirror that
When it happens
Trigger: PUT edit-artifact with a path that resolves to a directory (e.g. 'mnt/user-data/outputs/report/' with trailing content being a dir) or a special file created by sandbox tooling.
Common situations: Path-building bugs appending a filename to a directory path that already ends at the directory, artifacts listings surfacing directories as entries, or agent-created FIFOs/device nodes in outputs.
Related errors
- Only files in /mnt/user-data/outputs can be edited
- Path is not a file: {skill_file_path}
- Symlinked artifacts cannot be edited
- {e}
- Skill archives cannot be edited in the artifacts panel
AI-assisted analysis of bytedance/deer-flow@1dd6ba1acb (2026-08-14).
Data as JSON: /api/errors/b266ae0c898a405c.
Report an issue: GitHub.