charmbracelet/crush · error

could not create request: %w

Error message

could not create request: %w

What it means

Wraps an error from http.NewRequestWithContext inside the Hyper provider client's doGet (used by Get to fetch /api/v1/provider). The method, URL composition, and body are all static, so a failure here means the composed URL (r.baseURL + path) is not a valid URL. The etag and auth headers are set only after this point.

Source

Thrown at internal/config/hyper.go:151

		if refreshErr := r.refreshToken(ctx); refreshErr != nil {
			slog.Warn("Failed to refresh Hyper token", "error", refreshErr)
			return result, err
		}
		result, err = r.doGet(ctx, "")
	}
	return result, err
}

func (r realHyperClient) doGet(ctx context.Context, etag string) (catwalk.Provider, error) {
	var result catwalk.Provider
	req, err := http.NewRequestWithContext(
		ctx,
		http.MethodGet,
		r.baseURL+"/api/v1/provider",
		nil,
	)
	if err != nil {
		return result, fmt.Errorf("could not create request: %w", err)
	}
	xetag.Request(req, etag)
	if apiKey := r.resolveKey(); apiKey != "" {
		req.Header.Set("Authorization", "Bearer "+apiKey)
	}

	client := &http.Client{Timeout: 30 * time.Second}
	resp, err := client.Do(req)
	if err != nil {
		return result, fmt.Errorf("failed to make request: %w", err)
	}
	defer resp.Body.Close() //nolint:errcheck

	if resp.StatusCode == http.StatusNotModified {
		return result, catwalk.ErrNotModified
	}

	if resp.StatusCode == http.StatusUnauthorized {

View on GitHub (pinned to 7944b8e522)

Solutions

  1. Verify the Hyper base URL configuration (default https://api.hyperbolic.xyz) is set and well-formed.
  2. If the base URL comes from an env variable or config field, print it and correct it.
  3. Re-copy the Hyper API endpoint from their docs, ensuring https:// scheme and no trailing spaces.
  4. Check that no custom override in crushrc is clobbering the default with an invalid value.

Example fix

// before
baseURL := "" // unset -> invalid composed URL
// after
baseURL := "https://api.hyperbolic.xyz"
// composed: https://api.hyperbolic.xyz/api/v1/provider
Defensive patterns

Strategy: validation

Validate before calling

u, err := url.Parse(hyperBaseURL + "/api/v1/provider")
if err != nil || u.Host == "" {
    return fmt.Errorf("hyper baseURL %q produces invalid request URL", hyperBaseURL)
}

Type guard

func validHyperBase(raw string) bool {
    u, err := url.Parse(strings.TrimSpace(raw) + "/api/v1/provider")
    return err == nil && (u.Scheme == "http" || u.Scheme == "https") && u.Host != ""
}

Try / catch

result, err := client.Get(ctx)
if err != nil {
    if strings.Contains(err.Error(), "could not create request") {
        log.Fatalf("check hyper base URL configuration: %v", err)
    }
    return err
}

Prevention

When it happens

Trigger: Calling hyper client Get when r.baseURL is empty, malformed (bad scheme, control characters, spaces), or was misconfigured so the concatenation baseURL+"/api/v1/provider" fails to parse.

Common situations: Hyper base URL left empty because configuration did not resolve; a custom override with a typo like "hyper:/api" or trailing whitespace; env expansion producing a garbage value for the base URL.

Related errors


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