charmbracelet/crush · error

failed to download from URL: %w

Error message

failed to download from URL: %w

What it means

The HTTP client's Do call returned an error while attempting the GET request — the request never completed with an HTTP response. The error is wrapped with the job context so callers see the network-level cause (DNS, TLS, timeout, connection refused).

Source

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

				maxTimeout := 600 // 10 minutes
				if params.Timeout > maxTimeout {
					params.Timeout = maxTimeout
				}
				var cancel context.CancelFunc
				requestCtx, cancel = context.WithTimeout(ctx, time.Duration(params.Timeout)*time.Second)
				defer cancel()
			}

			req, err := http.NewRequestWithContext(requestCtx, "GET", params.URL, nil)
			if err != nil {
				return fantasy.ToolResponse{}, fmt.Errorf("failed to create request: %w", err)
			}

			req.Header.Set("User-Agent", "crush/1.0")

			resp, err := client.Do(req)
			if err != nil {
				return fantasy.ToolResponse{}, fmt.Errorf("failed to download from URL: %w", err)
			}
			defer resp.Body.Close()

			if resp.StatusCode != http.StatusOK {
				return fantasy.NewTextErrorResponse(fmt.Sprintf("Request failed with status code: %d", resp.StatusCode)), nil
			}

			// Create parent directories if they don't exist
			if err := os.MkdirAll(filepath.Dir(filePath), 0o755); err != nil {
				return fantasy.ToolResponse{}, fmt.Errorf("failed to create parent directories: %w", err)
			}

			// Create the output file
			outFile, err := os.Create(filePath)
			if err != nil {
				return fantasy.ToolResponse{}, fmt.Errorf("failed to create output file: %w", err)
			}
			defer outFile.Close()

View on GitHub (pinned to 7944b8e522)

Solutions

  1. Check the wrapped error for cause: context deadline exceeded means increase params.Timeout
  2. Verify network connectivity and DNS resolution for the host (curl the URL manually)
  3. If TLS is the issue, check certificate validity (don't disable verification)
  4. Retry transient failures or use a mirror URL

Example fix

// before
tool call with timeout: 5 (seconds) for a 2GB file
// after
tool call with timeout: 600 (seconds)
Defensive patterns

Strategy: retry

Validate before calling

// cheap pre-check before the tool call
conn, err := net.DialTimeout("tcp", host+":443", 5*time.Second)
if err != nil { return fmt.Errorf("host unreachable: %v", err) }
conn.Close()

Try / catch

if err != nil {
    if errors.Is(err, context.DeadlineExceeded) {
        return fmt.Errorf("download timed out; raise timeout (max 600s): %w", err)
    }
    var netErr net.Error
    if errors.As(err, &netErr) && netErr.Timeout() {
        // retry with backoff
    }
    return fmt.Errorf("download failed: %w", err)
}

Prevention

When it happens

Trigger: DNS resolution failure, connection refused/timeout, TLS handshake error, or the request context (params.Timeout, max 600s; client default 5 min) expired during the request.

Common situations: Target host unreachable or offline; corporate proxy/firewall blocking outbound HTTPS; invalid or expired TLS certificates; downloads exceeding the configured timeout on slow links; no network access in sandboxed environments.

Understand the failure class

Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.

Related errors


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