wavetermdev/waveterm · error
failed to capture screenshot: %w
Error message
failed to capture screenshot: %w
What it means
This error wraps any failure from the wshclient.CaptureBlockScreenshotCommand RPC, which asks the Wave tab's route to render a block (widget) and return screenshot data. It is thrown by the AI capture_screenshot tool when the underlying RPC returns an error — e.g. the tab route is unavailable, the block cannot be resolved/rendered, or the RPC times out (5s context deadline). The original cause is preserved via %w so unwrap it for details.
Source
Thrown at pkg/aiusechat/tools_screenshot.go:45
return "", fmt.Errorf("missing or invalid widget_id parameter")
}
ctx, cancelFn := context.WithTimeout(context.Background(), 5*time.Second)
defer cancelFn()
fullBlockId, err := wcore.ResolveBlockIdFromPrefix(ctx, tabId, blockIdPrefix)
if err != nil {
return "", err
}
rpcClient := wshclient.GetBareRpcClient()
screenshotData, err := wshclient.CaptureBlockScreenshotCommand(
rpcClient,
wshrpc.CommandCaptureBlockScreenshotData{BlockId: fullBlockId},
&wshrpc.RpcOpts{Route: wshutil.MakeTabRouteId(tabId)},
)
if err != nil {
return "", fmt.Errorf("failed to capture screenshot: %w", err)
}
return screenshotData, nil
}
}
func GetCaptureScreenshotToolDefinition(tabId string) uctypes.ToolDefinition {
return uctypes.ToolDefinition{
Name: "capture_screenshot",
DisplayName: "Capture Screenshot",
Description: "Capture a screenshot of a widget and return it as an image",
ToolLogName: "gen:screenshot",
Strict: true,
InputSchema: map[string]any{
"type": "object",
"properties": map[string]any{
"widget_id": map[string]any{
"type": "string",View on GitHub (pinned to a4447c1563)
Solutions
- Unwrap the error (%v with errors.Unwrap or errors.As) to see the root cause (timeout vs not-found vs route error)
- Verify the widget_id/blockId is valid and the block still exists in the given tab
- Confirm the tab is open and its wsh route is connected before calling the RPC
- Retry once if the failure was a deadline/timeout, or increase the 5s context timeout
- Check that the block type actually supports screenshot capture
Example fix
// before
screenshotData, err := wshclient.CaptureBlockScreenshotCommand(rpcClient, wshrpc.CommandCaptureBlockScreenshotData{BlockId: fullBlockId}, &wshrpc.RpcOpts{Route: wshutil.MakeTabRouteId(tabId)})
if err != nil { return "", fmt.Errorf("failed to capture screenshot: %w", err) }
// after
screenshotData, err := wshclient.CaptureBlockScreenshotCommand(rpcClient, wshrpc.CommandCaptureBlockScreenshotData{BlockId: fullBlockId}, &wshrpc.RpcOpts{Route: wshutil.MakeTabRouteId(tabId), TimeoutMs: 10000})
if err != nil { return "", fmt.Errorf("failed to capture screenshot for block %s: %w", fullBlockId, err) } Defensive patterns
Strategy: try-catch
Validate before calling
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
if _, err := wcore.ResolveBlockIdFromPrefix(ctx, tabId, widgetId); err != nil {
return fmt.Errorf("invalid widget %s in tab %s: %w", widgetId, tabId, err)
} Type guard
func isTimeoutErr(err error) bool {
var ne net.Error
return errors.As(err, &ne) && ne.Timeout()
} Try / catch
screenshot, err := captureTool(input)
if err != nil {
if isTimeoutErr(err) {
// retry once with longer deadline
}
log.Printf("screenshot capture failed: %v", err)
return fmt.Errorf("capture_screenshot unavailable: %w", err)
} Prevention
- Validate the widget_id resolves to an existing block before capturing
- Ensure the target tab is open and its wsh route is connected
- Use a retry with backoff for deadline-type failures
- Keep the 5s context timeout in mind; avoid capturing blocks that block rendering
When it happens
Trigger: Calling the capture_screenshot AI tool where CaptureBlockScreenshotCommand over RpcOpts{Route: MakeTabRouteId(tabId)} fails: tab route not connected, invalid/removed block id, renderer failure, or the 5-second context timeout elapsing before a response.
Common situations: AI agent passes a stale widget_id for a block that was closed; the target tab was closed or the wsh route is down; the block contents hang (e.g. a stuck terminal) causing the 5s deadline to expire; running outside the Wave app where no bare RPC client connection exists.
Related errors
- failed to get terminal scrollback: %w
- call ${methodName} error: ${respData.error}
- failed to list workspaces: %v
- failed to list blocks from all %d workspace(s)
- reinstalling connection: %w
AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01).
Data as JSON: /api/errors/9d4c7f8653484d56.
Report an issue: GitHub.