{"record":{"id":"e6dc3d8417203471","repo":"tinyhumansai/openhuman","slug":"artifact-get-e","errorCode":null,"errorMessage":"artifact_get: {e}","messagePattern":"artifact_get: (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"src/openhuman/agent/artifacts/tools.rs","lineNumber":139,"sourceCode":"         first to discover ids.\"\n    }\n\n    fn parameters_schema(&self) -> serde_json::Value {\n        json!({\n            \"type\": \"object\",\n            \"properties\": {\n                \"artifact_id\": { \"type\": \"string\", \"description\": \"The artifact id (UUID) to fetch.\" }\n            },\n            \"required\": [\"artifact_id\"]\n        })\n    }\n\n    async fn execute(&self, args: serde_json::Value) -> anyhow::Result<ToolResult> {\n        log::debug!(\"[tool][artifacts] get invoked\");\n        let id = read_required_str(&args, \"artifact_id\")?;\n        let outcome = ops::ai_get_artifact(&self.config, &id)\n            .await\n            .map_err(|e| anyhow::anyhow!(\"artifact_get: {e}\"))?;\n        Ok(ToolResult::success(serde_json::to_string(&outcome.value)?))\n    }\n\n    fn is_concurrency_safe(&self, _args: &serde_json::Value) -> bool {\n        true\n    }\n}\n\n/// Delete an artifact directory and all its contents. **Irreversible** —\n/// ships default-OFF (`Dangerous`).\npub struct ArtifactDeleteTool {\n    config: Arc<Config>,\n}\n\nimpl ArtifactDeleteTool {\n    pub fn new(config: Arc<Config>) -> Self {\n        Self { config }\n    }","sourceCodeStart":121,"sourceCodeEnd":157,"githubUrl":"https://github.com/tinyhumansai/openhuman/blob/a221052e0df5b1f7598fceba7329fd1af95d6699/src/openhuman/agent/artifacts/tools.rs#L121-L157","documentation":"Wrapper around `ops::ai_get_artifact` failing in ArtifactGetTool::execute after `read_required_str` already validated `artifact_id`. The dominant inner failure is store::get_artifact's \"artifact not found or unreadable id={id}\" (store.rs:242): no `<workspace>/artifacts/<id>/meta.json`, or the file exists but is unreadable/unparseable. It also covers an artifacts_root creation failure.","triggerScenarios":"Agent calls artifact_get with a hallucinated or truncated UUID; the artifact directory was deleted out-of-band (user cleaned artifacts/, another delete raced); meta.json is corrupted (partial write) or permissions deny the read.","commonSituations":"Model reusing an id from an earlier session whose workspace differs (workspace_dir changed via --workspace/env); concurrent artifact_delete; disk-full during a previous meta.json write leaving invalid JSON.","solutions":["Call artifact_list first and use an id that is currently present.","Confirm the id is the full UUID returned in the listing, not a truncated prefix.","Verify the same workspace: ids are scoped to `<workspace>/artifacts/`, so a changed workspace_dir invalidates old ids.","If meta.json is corrupted, remove the artifact dir via artifact_delete (or manually) and regenerate.","Check filesystem permissions on `<workspace>/artifacts/<id>/`."],"exampleFix":"# before\n{ \"artifact_id\": \"550e8400\" }            # truncated/hallucinated -> not found\n# after\n# 1) artifact_list -> take meta.id\n{ \"artifact_id\": \"550e8400-e29b-41d4-a716-446655440000\" }","handlingStrategy":"validation","validationCode":"// Resolve the id from a live listing before calling get:\nlet listing = ops::ai_list_artifacts(&config, 0, 500, None).await?;\nlet known: HashSet<String> = listing.value.artifacts.iter().map(|a| a.id.clone()).collect();\nif !known.contains(&wanted_id) {\n    anyhow::bail!(\"artifact {wanted_id} not in current workspace listing\");\n}","typeGuard":"fn is_plausible_artifact_id(s: &str) -> bool {\n    // ids are UUIDs persisted as <workspace>/artifacts/<id>/meta.json\n    s.len() == 36 && s.matches('-').count() == 4\n}","tryCatchPattern":"match ops::ai_get_artifact(&config, &id).await {\n    Ok(meta) => meta,\n    Err(e) if e.to_string().contains(\"not found or unreadable\") => {\n        // stale/hallucinated id: re-list, pick by title, or tell the model the artifact is gone\n    }\n    Err(e) => return Err(anyhow!(\"artifact_get: {e}\")),\n}","preventionTips":["Always source ids from artifact_list in the same workspace.","Remember ids are workspace-scoped — changing workspace_dir invalidates them.","Treat 'not found or unreadable' as a cache miss: re-list and retry once."],"tags":["rust","agent-tools","artifacts","not-found","filesystem"],"backgroundTag":null,"analyzedSha":"a221052e0df5b1f7598fceba7329fd1af95d6699","analyzedAt":"2026-08-16T12:47:06.542Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}