{"record":{"id":"e58b4730c9b2bf1e","repo":"charmbracelet/crush","slug":"session-id-is-required-for-accessing-files-outside","errorCode":null,"errorMessage":"session ID is required for accessing files outside working directory","messagePattern":"session ID is required for accessing files outside working directory","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/agent/tools/view.go","lineNumber":132,"sourceCode":"\n\t\t\t// Check if file 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.ToolResponse{}, fmt.Errorf(\"error resolving working directory: %w\", err)\n\t\t\t}\n\n\t\t\tabsFilePath, err := filepath.Abs(filePath)\n\t\t\tif err != nil {\n\t\t\t\treturn fantasy.ToolResponse{}, fmt.Errorf(\"error resolving file path: %w\", err)\n\t\t\t}\n\n\t\t\trelPath, err := filepath.Rel(absWorkingDir, absFilePath)\n\t\t\tisOutsideWorkDir := err != nil || strings.HasPrefix(relPath, \"..\")\n\t\t\tisSkillFile := isInSkillsPath(absFilePath, skillsPaths)\n\n\t\t\tsessionID := GetSessionFromContext(ctx)\n\t\t\tif sessionID == \"\" {\n\t\t\t\treturn fantasy.ToolResponse{}, fmt.Errorf(\"session ID is required for accessing files outside working directory\")\n\t\t\t}\n\n\t\t\t// Request permission for files outside working directory, unless it's a skill file.\n\t\t\tif isOutsideWorkDir && !isSkillFile {\n\t\t\t\tgranted, permReqErr := 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:        absFilePath,\n\t\t\t\t\t\tToolCallID:  call.ID,\n\t\t\t\t\t\tToolName:    ViewToolName,\n\t\t\t\t\t\tAction:      \"read\",\n\t\t\t\t\t\tDescription: fmt.Sprintf(\"Read file outside working directory: %s\", absFilePath),\n\t\t\t\t\t\tParams:      ViewPermissionsParams(params),\n\t\t\t\t\t},\n\t\t\t\t)\n\t\t\t\tif permReqErr != nil {\n\t\t\t\t\treturn fantasy.ToolResponse{}, permReqErr","sourceCodeStart":114,"sourceCodeEnd":150,"githubUrl":"https://github.com/charmbracelet/crush/blob/7944b8e52225d8805e31eacbf7ef24856b0dfb7a/internal/agent/tools/view.go#L114-L150","documentation":"The view tool requires a session ID before it can run its permission flow for files outside the working directory. The session ID is fetched unconditionally (even for in-workdir files), so an empty context value fails the call regardless of the target path. Like error 200, this indicates the tool was invoked without the agent's session-scoped context.","triggerScenarios":"Invoking the view tool directly (tests, custom runners) without SetSessionInContext; a custom agent path that builds tool contexts without the session ID.","commonSituations":"Custom agent integrations; test harnesses calling the tool function directly; regressions after refactoring context plumbing.","solutions":["Invoke the tool through the standard coordinator path that injects the session ID","Set the session ID in the context before executing (SetSessionInContext)","Report as a bug if it happens in normal Crush usage"],"exampleFix":"// before\ntool.Execute(ctx, call) // no session in ctx\n// after\ntool.Execute(tools.SetSessionInContext(ctx, sessionID), call)","handlingStrategy":"validation","validationCode":"if tools.GetSessionFromContext(ctx) == \"\" {\n    return errors.New(\"view tool requires a session ID in context\")\n}","typeGuard":"func hasSession(ctx context.Context) bool {\n    return tools.GetSessionFromContext(ctx) != \"\"\n}","tryCatchPattern":"if err != nil && strings.Contains(err.Error(), \"session ID is required\") {\n    return tool.Execute(tools.SetSessionInContext(ctx, sessionID), call)\n}","preventionTips":["Route tool execution through the coordinator which injects the session ID","In custom runners, set the session context value before every tool call","Cover context wiring in integration tests"],"tags":["go","context","permissions","session"],"backgroundTag":"missing-context-value","analyzedSha":"7944b8e52225d8805e31eacbf7ef24856b0dfb7a","analyzedAt":"2026-08-29T12:48:59.079Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}