charmbracelet/crush · error

session ID is required for downloading files

Error message

session ID is required for downloading files

What it means

The download tool requires a session ID, obtained from the request context via GetSessionFromContext, to record the permission request for writing the downloaded file. If the context carries no session ID the tool refuses to run. This is an internal invariant: tool invocations are normally made by the agent, which always sets the session.

Source

Thrown at internal/agent/tools/download.go:87

			if params.URL == "" {
				return fantasy.NewTextErrorResponse("URL parameter is required"), nil
			}

			if params.FilePath == "" {
				return fantasy.NewTextErrorResponse("file_path parameter is required"), nil
			}

			if !strings.HasPrefix(params.URL, "http://") && !strings.HasPrefix(params.URL, "https://") {
				return fantasy.NewTextErrorResponse("URL must start with http:// or https://"), nil
			}

			filePath := filepathext.SmartJoin(workingDir, params.FilePath)
			relPath, _ := filepath.Rel(workingDir, filePath)
			relPath = filepath.ToSlash(cmp.Or(relPath, filePath))

			sessionID := GetSessionFromContext(ctx)
			if sessionID == "" {
				return fantasy.ToolResponse{}, fmt.Errorf("session ID is required for downloading files")
			}

			p, err := permissions.Request(
				ctx,
				permission.CreatePermissionRequest{
					SessionID:   sessionID,
					Path:        filePath,
					ToolName:    DownloadToolName,
					Action:      "download",
					Description: fmt.Sprintf("Download file from URL: %s to %s", params.URL, filePath),
					Params:      DownloadPermissionsParams(params),
				},
			)
			if err != nil {
				return fantasy.ToolResponse{}, err
			}
			if !p {
				return NewPermissionDeniedResponse(), nil

View on GitHub (pinned to 7944b8e522)

Solutions

  1. Invoke the tool through the normal agent/coordinator path which sets the session ID in the context
  2. In tests, attach the session ID to the context the same way the agent does before calling the handler
  3. Check that the context isn't being recreated/stripped between permission setup and tool execution

Example fix

// before
resp, _ := tool.Handle(ctx, params, call)
// after
ctx = WithSessionContext(ctx, "my-session-id")
resp, _ := tool.Handle(ctx, params, call)
Defensive patterns

Strategy: validation

Validate before calling

// Go (caller side)
if GetSessionFromContext(ctx) == "" {
    return nil, fmt.Errorf("attach a session ID to ctx before invoking the download tool")
}

Try / catch

resp, err := tool.Handle(ctx, params, call)
if err != nil && strings.Contains(err.Error(), "session ID is required") {
    ctx = WithSessionContext(ctx, sessionID)
    resp, err = tool.Handle(ctx, params, call)
}

Prevention

When it happens

Trigger: The download tool's handler is invoked with a context.Context that has no session ID attached — e.g. calling the tool function directly in tests or scripts, or an agent wiring path that skips GetSessionFromContext's context key.

Common situations: Unit/integration tests invoking the tool handler without the session context key; embedding the tool in a custom agent that doesn't propagate the session ID; regressions after refactoring context plumbing.

Related errors


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