{"record":{"id":"f7198d606255594c","repo":"charmbracelet/crush","slug":"session-id-is-required-for-accessing-directories-o","errorCode":null,"errorMessage":"session ID is required for accessing directories outside working directory","messagePattern":"session ID is required for accessing directories outside working directory","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/agent/tools/ls.go","lineNumber":102,"sourceCode":"\t\t\tsearchPath = filepathext.SmartJoin(workingDir, searchPath)\n\n\t\t\t// Check if directory is outside working directory and request permission if needed\n\t\t\tabsWorkingDir, err := filepath.Abs(workingDir)\n\t\t\tif err != nil {\n\t\t\t\treturn fantasy.NewTextErrorResponse(fmt.Sprintf(\"error resolving working directory: %v\", err)), nil\n\t\t\t}\n\n\t\t\tabsSearchPath, err := filepath.Abs(searchPath)\n\t\t\tif err != nil {\n\t\t\t\treturn fantasy.NewTextErrorResponse(fmt.Sprintf(\"error resolving search path: %v\", err)), nil\n\t\t\t}\n\n\t\t\trelPath, err := filepath.Rel(absWorkingDir, absSearchPath)\n\t\t\tif err != nil || strings.HasPrefix(relPath, \"..\") {\n\t\t\t\t// Directory is outside working directory, request permission\n\t\t\t\tsessionID := GetSessionFromContext(ctx)\n\t\t\t\tif sessionID == \"\" {\n\t\t\t\t\treturn fantasy.ToolResponse{}, fmt.Errorf(\"session ID is required for accessing directories outside working directory\")\n\t\t\t\t}\n\n\t\t\t\tgranted, err := permissions.Request(\n\t\t\t\t\tctx,\n\t\t\t\t\tpermission.CreatePermissionRequest{\n\t\t\t\t\t\tSessionID:   sessionID,\n\t\t\t\t\t\tPath:        absSearchPath,\n\t\t\t\t\t\tToolCallID:  call.ID,\n\t\t\t\t\t\tToolName:    LSToolName,\n\t\t\t\t\t\tAction:      \"list\",\n\t\t\t\t\t\tDescription: fmt.Sprintf(\"List directory outside working directory: %s\", absSearchPath),\n\t\t\t\t\t\tParams:      LSPermissionsParams(params),\n\t\t\t\t\t},\n\t\t\t\t)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn fantasy.ToolResponse{}, err\n\t\t\t\t}\n\t\t\t\tif !granted {","sourceCodeStart":84,"sourceCodeEnd":120,"githubUrl":"https://github.com/charmbracelet/crush/blob/7944b8e52225d8805e31eacbf7ef24856b0dfb7a/internal/agent/tools/ls.go#L84-L120","documentation":"The ls tool allows free directory access inside the configured working directory, but when the resolved path escapes it (filepath.Rel yields a '..'-prefixed path or fails), a permission request tied to a session is required. Without a session ID in the context the tool cannot create that request and fails with this error.","triggerScenarios":"Calling the ls tool with a path outside cfg.WorkingDir() while the context has no session ID, e.g. direct tool invocation in tests or scripts.","commonSituations":"Pointing ls at /etc or a sibling project root from a non-session execution path; running the tool handler in isolation without session plumbing.","solutions":["Keep the search path inside the working directory so the permission path is never taken.","Run the tool through the agent pipeline so GetSessionFromContext returns a valid session.","In tests, inject a session ID into the context before calling the tool."],"exampleFix":"// before\nListDirectory(\"/etc\", params) // outside working dir, no session in ctx\n// after\nctx = WithSession(ctx, sessionID) // or use a path under WorkingDir()","handlingStrategy":"validation","validationCode":"abs, _ := filepath.Abs(path)\nrel, err := filepath.Rel(workDir, abs)\nif err != nil || strings.HasPrefix(rel, \"..\") {\n    // ensure session context present before calling\n}","typeGuard":"func insideWorkDir(path, workDir string) bool {\n    rel, err := filepath.Rel(workDir, path)\n    return err == nil && !strings.HasPrefix(rel, \"..\")\n}","tryCatchPattern":"if err != nil {\n    if strings.Contains(err.Error(), \"session ID is required\") { /* run within a session */ }\n}","preventionTips":["Keep tool paths within the configured working directory","Inject session IDs when embedding tools in custom flows","Grant permissions ahead of time via config allow-lists"],"tags":["permissions","filesystem","session"],"backgroundTag":"path-outside-working-directory","analyzedSha":"7944b8e52225d8805e31eacbf7ef24856b0dfb7a","analyzedAt":"2026-08-29T12:48:59.079Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}