charmbracelet/crush · error

create request: %w

Error message

create request: %w

What it means

InitiateDeviceAuth builds the HTTP POST to the Hyper OAuth device endpoint with a JSON body containing the device name. If http.NewRequestWithContext itself fails (malformed URL or invalid reader), the error is wrapped as "create request". This is a construction-time failure — no network I/O has happened yet.

Source

Thrown at internal/oauth/hyper/device.go:48

type TokenResponse struct {
	RefreshToken     string `json:"refresh_token,omitempty"`
	UserID           string `json:"user_id"`
	OrganizationID   string `json:"organization_id"`
	OrganizationName string `json:"organization_name"`
	Error            string `json:"error,omitempty"`
	ErrorDescription string `json:"error_description,omitempty"`
}

// InitiateDeviceAuth calls the /device/auth endpoint to start the device flow.
func InitiateDeviceAuth(ctx context.Context) (*DeviceAuthResponse, error) {
	url := hyper.BaseURL() + "/device/auth"

	req, err := http.NewRequestWithContext(
		ctx, http.MethodPost, url,
		strings.NewReader(fmt.Sprintf(`{"device_name":%q}`, deviceName())),
	)
	if err != nil {
		return nil, fmt.Errorf("create request: %w", err)
	}

	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("User-Agent", "crush")

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

	body, err := io.ReadAll(io.LimitReader(resp.Body, 1<<20))
	if err != nil {
		return nil, fmt.Errorf("read response: %w", err)
	}

	if resp.StatusCode != http.StatusOK {

View on GitHub (pinned to 7944b8e522)

Solutions

  1. Print/inspect the full URL string passed to InitiateDeviceAuth and fix invalid characters or empty scheme
  2. Verify the endpoint configuration source (env var, config file) for typos
  3. If a proxy base URL is configurable, validate it parses with url.Parse before calling
  4. Retry is pointless here — correct the configuration and call again

Example fix

// before
u := os.Getenv("HYPER_API_URL")
auth, err := InitiateDeviceAuth(ctx, client, u)
// after
u := os.Getenv("HYPER_API_URL")
if _, err := url.Parse(u); err != nil || u == "" {
    return fmt.Errorf("invalid HYPER_API_URL: %q", u)
}
auth, err := InitiateDeviceAuth(ctx, client, u)
Defensive patterns

Strategy: validation

Validate before calling

func validateEndpoint(base string) error {
    if base == "" { return fmt.Errorf("endpoint empty") }
    u, err := url.Parse(base)
    if err != nil { return err }
    if u.Scheme != "https" || u.Host == "" { return fmt.Errorf("bad endpoint: %q", base) }
    return nil
}
// call before InitiateDeviceAuth

Try / catch

auth, err := InitiateDeviceAuth(ctx, client, endpoint)
if err != nil && strings.Contains(err.Error(), "create request") {
    return fmt.Errorf("misconfigured Hyper endpoint %q: %w", endpoint, err)
}

Prevention

When it happens

Trigger: http.NewRequestWithContext returns an error, practically always because the configured base URL plus path forms an invalid URL (unparsable scheme/host, control characters) or a bad context value.

Common situations: Misconfigured endpoint URL in settings/env (typo, empty, or containing whitespace/newline); an interceptor or test harness supplying a bogus URL; malformed context key affecting header interpolation.

Related errors


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