{"record":{"id":"3eb38b4a91ff63b1","repo":"Tencent/WeKnora","slug":"sandbox-workspace-write-path-q-is-a-directory-n","errorCode":null,"errorMessage":"sandbox: workspace write path %q is a directory, not a file","messagePattern":"sandbox: workspace write path %q is a directory, not a file","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/sandbox/session_manager.go","lineNumber":1025,"sourceCode":"\tif clean == SessionInputRoot || strings.HasPrefix(clean, SessionInputRoot+\"/\") {\n\t\treturn clean, nil\n\t}\n\treturn \"\", fmt.Errorf(\n\t\t\"sandbox: session input path %q is outside %s\",\n\t\tfilePath, SessionInputRoot,\n\t)\n}\n\n// cleanSessionWorkspaceWritePath keeps model-authored writes inside the\n// session workspace and out of the attachment tree. Validation is lexical\n// (path.Clean plus prefix checks), matching cleanSessionWorkDir.\nfunc cleanSessionWorkspaceWritePath(filePath string) (string, error) {\n\tclean := path.Clean(strings.TrimSpace(filePath))\n\tif !path.IsAbs(clean) || clean == \".\" || clean == \"/\" {\n\t\treturn \"\", fmt.Errorf(\"sandbox: workspace write path %q must be an absolute file path\", filePath)\n\t}\n\tif clean == SessionWorkspaceRoot || clean == SessionOutputRoot || clean == SessionInputRoot {\n\t\treturn \"\", fmt.Errorf(\"sandbox: workspace write path %q is a directory, not a file\", filePath)\n\t}\n\tif !strings.HasPrefix(clean, SessionWorkspaceRoot+\"/\") {\n\t\treturn \"\", fmt.Errorf(\"sandbox: workspace write path %q is outside %s\", filePath, SessionWorkspaceRoot)\n\t}\n\tif strings.HasPrefix(clean, SessionInputRoot+\"/\") {\n\t\treturn \"\", fmt.Errorf(\"sandbox: session input %s is read-only\", SessionInputRoot)\n\t}\n\treturn clean, nil\n}\n\n// cleanSessionWorkDir keeps shell_exec inside directories we are willing to let\n// an agent work in. Ordinary sessions get /workspace only.\n//\n// Validation is lexical (path.Clean plus prefix checks): a symlink under an\n// allowed root that resolves elsewhere at execution time is not detected and\n// that is intentional. The only caller that passes allowSkillsRoot also passes\n// AsRoot and runs arbitrary install shell commands, so a symlink would grant\n// nothing those commands cannot already reach via cd or absolute paths. For","sourceCodeStart":1007,"sourceCodeEnd":1043,"githubUrl":"https://github.com/Tencent/WeKnora/blob/988cbb03305e055d8ebb7d46d9ac6cc0803cd074/internal/sandbox/session_manager.go#L1007-L1043","documentation":"Validation guard in cleanSessionWorkspaceWritePath: the cleaned workspace write path resolves to a directory root (e.g. the workspace root itself or a '.'-equivalent), so it names a directory rather than a file. Writes must target a concrete file path inside the session workspace.","triggerScenarios":"Thrown at internal/sandbox/session_manager.go:1025 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Append a file name to the workspace path before writing","Choose a file path one or more levels below the workspace root"],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"988cbb03305e055d8ebb7d46d9ac6cc0803cd074","analyzedAt":"2026-09-02T14:41:08.344Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}