langchain-ai/deepagents · error · OSError
temporary artifact identity changed
Error message
temporary artifact identity changed
What it means
Raised by `_delete_temp_artifact_file` when an `lstat` of the artifact's path does not match the identity recorded at creation: the file is no longer a regular file, or its `st_dev`/`st_ino` differ from the `file_device`/`file_inode` stored in the `AutoTempArtifact`. The library throws this to prevent a symlink-swap or replacement race from causing it to unlink the wrong file.
Source
Thrown at libs/code/deepagents_code/auto_mode.py:1124
)
]
}
)
def _delete_temp_artifact_file(artifact: AutoTempArtifact) -> None:
file_path = Path(artifact["file_path"])
if not file_path.name.startswith(_TEMP_ARTIFACT_PREFIX):
msg = "temporary artifact provenance is invalid"
raise OSError(msg)
file_stat = file_path.lstat()
if (
not stat.S_ISREG(file_stat.st_mode)
or file_stat.st_dev != artifact["file_device"]
or file_stat.st_ino != artifact["file_inode"]
):
msg = "temporary artifact identity changed"
raise OSError(msg)
file_path.unlink()
def _summarize_value(key: str, value: object, *, depth: int = 0) -> object:
if depth >= _MAX_ARGUMENT_DEPTH:
return "[nested value omitted]"
if _SECRET_KEY_RE.search(key):
return "[redacted credential value]"
if key.lower() in {"content", "new_string", "old_string", "new_str"} and isinstance(
value, str
):
return {"character_count": len(value), "content_omitted": True}
if isinstance(value, str):
return value[:4000]
if isinstance(value, Mapping):
return {
str(child_key): _summarize_value(
str(child_key), child_value, depth=depth + 1View on GitHub (pinned to a1af029e6e)
Solutions
- Retry the whole flow: re-create the artifact with `create_temp_artifact` rather than reusing the stale record
- Check for temp-file cleaners (`systemd-tmpfiles`, `tmpwatch`, cron scripts) racing the agent and exclude the prefix or shorten the artifact lifetime
- If the file is legitimately already gone, treat the deletion as done and drop the stale artifact record from state
- Never delete the same artifact record twice — track the returned allocation lifecycle
Defensive patterns
Strategy: try-catch
Validate before calling
import os, stat
from pathlib import Path
def artifact_identity_intact(artifact) -> bool:
try:
st = Path(artifact["file_path"]).lstat()
except FileNotFoundError:
return False
return stat.S_ISREG(st.st_mode) and st.st_dev == artifact["file_device"] and st.st_ino == artifact["file_inode"] Try / catch
try:
delete_temp_artifact(artifact)
except OSError as exc:
if "identity changed" in str(exc):
discard_stale_record() # file already gone or replaced; nothing safe to unlink
else:
raise Prevention
- Delete artifacts promptly in the same turn they are created
- Exclude the library's temp prefix from tmpfile cleaners (systemd-tmpfiles, tmpwatch)
- Never delete the same artifact record twice
- Avoid moving or re-creating files under the recorded artifact path
When it happens
Trigger: Calling `delete_temp_artifact` after the temp file was deleted and recreated, replaced by a symlink or different inode, or moved/renamed — any change of device or inode between `create_temp_artifact` and the delete call.
Common situations: Another process or a cleanup daemon (`tmpwatch`, `systemd-tmpfiles`) removing and re-creating files in the temp dir; tests reusing artifact records across temp dirs; the same artifact record being deleted twice, where the second delete fails because the original inode is gone; an attacker swapping the file (the check exists for this).
Related errors
- temporary artifact is not a regular file
- temporary artifact is not owned by this user
- temporary artifact permissions are too broad
- debug log directory is not a real directory: {path}
- debug log directory is not owned by the current user: {path}
AI-assisted analysis of langchain-ai/deepagents@a1af029e6e (2026-08-29).
Data as JSON: /api/errors/0447813fa1f2e266.
Report an issue: GitHub.