{"record":{"id":"f8157a5ac25a83e3","repo":"tinyhumansai/openhuman","slug":"failed-to-canonicalize-workspace-e","errorCode":null,"errorMessage":"Failed to canonicalize workspace: {e}","messagePattern":"Failed to canonicalize workspace: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/openhuman/tools/impl/filesystem/update_memory_md.rs","lineNumber":250,"sourceCode":"        let content = args\n            .get(\"content\")\n            .and_then(|v| v.as_str())\n            .ok_or_else(|| anyhow::anyhow!(\"Missing 'content' parameter\"))?;\n\n        // Guard: only allow MEMORY.md and SKILL.md.\n        if !ALLOWED_FILES.contains(&file) {\n            return Ok(ToolResult::error(format!(\n                \"File '{file}' is not allowed. Permitted files: MEMORY.md, SKILL.md\"\n            )));\n        }\n\n        let target_path = workspace_dir.join(file);\n\n        // Prevent symlink-based workspace escape.\n        let workspace_canon = self\n            .workspace_dir_for_context(context)\n            .canonicalize()\n            .map_err(|e| anyhow::anyhow!(\"Failed to canonicalize workspace: {e}\"))?;\n        // Check parent dir exists and canonicalize to detect symlinks.\n        let parent = target_path.parent().unwrap_or(&workspace_dir);\n        let parent_canon = parent\n            .canonicalize()\n            .unwrap_or_else(|_| parent.to_path_buf());\n        if !parent_canon.starts_with(&workspace_canon) {\n            return Ok(ToolResult::error(format!(\n                \"File path '{file}' resolves outside workspace\"\n            )));\n        }\n\n        tracing::debug!(\"[update_memory_md] action={action} file={file} path={target_path:?}\");\n\n        // #4458: serialize the whole read-modify-write against concurrent runs\n        // targeting the same workspace. The guard is held across read + atomic\n        // write so no interleaving append can be lost.\n        let lock = workspace_write_lock(&workspace_dir);\n        let _guard = lock.lock().await;","sourceCodeStart":232,"sourceCodeEnd":268,"githubUrl":"https://github.com/tinyhumansai/openhuman/blob/749120085864ce16e0f273c7b86fac7740b39c5b/src/openhuman/tools/impl/filesystem/update_memory_md.rs#L232-L268","documentation":"Before any read-modify-write, the tool canonicalizes the workspace root so the target path (workspace + allowed file) can be checked against symlink-based escapes. If std::fs::canonicalize fails — typically the workspace directory was deleted, moved, or is unreadable — this error aborts the operation as a security guard failure, not a content problem.","triggerScenarios":"Thrown at src/openhuman/tools/impl/filesystem/update_memory_md.rs:250 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Verify the workspace directory still exists and is readable/writable","Recreate or re-resolve the workspace root, then retry the tool call","If the workspace moved, restart the session so tools get the fresh path"],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"749120085864ce16e0f273c7b86fac7740b39c5b","analyzedAt":"2026-08-17T21:21:45.363Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}