charmbracelet/crush · error

session ID is required for accessing directories outside wor

Error message

session ID is required for accessing directories outside working directory

What it means

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.

Source

Thrown at internal/agent/tools/ls.go:102

			searchPath = filepathext.SmartJoin(workingDir, searchPath)

			// Check if directory is outside working directory and request permission if needed
			absWorkingDir, err := filepath.Abs(workingDir)
			if err != nil {
				return fantasy.NewTextErrorResponse(fmt.Sprintf("error resolving working directory: %v", err)), nil
			}

			absSearchPath, err := filepath.Abs(searchPath)
			if err != nil {
				return fantasy.NewTextErrorResponse(fmt.Sprintf("error resolving search path: %v", err)), nil
			}

			relPath, err := filepath.Rel(absWorkingDir, absSearchPath)
			if err != nil || strings.HasPrefix(relPath, "..") {
				// Directory is outside working directory, request permission
				sessionID := GetSessionFromContext(ctx)
				if sessionID == "" {
					return fantasy.ToolResponse{}, fmt.Errorf("session ID is required for accessing directories outside working directory")
				}

				granted, err := permissions.Request(
					ctx,
					permission.CreatePermissionRequest{
						SessionID:   sessionID,
						Path:        absSearchPath,
						ToolCallID:  call.ID,
						ToolName:    LSToolName,
						Action:      "list",
						Description: fmt.Sprintf("List directory outside working directory: %s", absSearchPath),
						Params:      LSPermissionsParams(params),
					},
				)
				if err != nil {
					return fantasy.ToolResponse{}, err
				}
				if !granted {

View on GitHub (pinned to 7944b8e522)

Solutions

  1. Keep the search path inside the working directory so the permission path is never taken.
  2. Run the tool through the agent pipeline so GetSessionFromContext returns a valid session.
  3. In tests, inject a session ID into the context before calling the tool.

Example fix

// before
ListDirectory("/etc", params) // outside working dir, no session in ctx
// after
ctx = WithSession(ctx, sessionID) // or use a path under WorkingDir()
Defensive patterns

Strategy: validation

Validate before calling

abs, _ := filepath.Abs(path)
rel, err := filepath.Rel(workDir, abs)
if err != nil || strings.HasPrefix(rel, "..") {
    // ensure session context present before calling
}

Type guard

func insideWorkDir(path, workDir string) bool {
    rel, err := filepath.Rel(workDir, path)
    return err == nil && !strings.HasPrefix(rel, "..")
}

Try / catch

if err != nil {
    if strings.Contains(err.Error(), "session ID is required") { /* run within a session */ }
}

Prevention

When it happens

Trigger: 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.

Common situations: Pointing ls at /etc or a sibling project root from a non-session execution path; running the tool handler in isolation without session plumbing.

Related errors


AI-assisted analysis of charmbracelet/crush@7944b8e522 (2026-08-29). Data as JSON: /api/errors/f7198d606255594c. Report an issue: GitHub.