plandex-ai/plandex · error

error creating request: %w

Error message

error creating request: %w

What it means

The library constructs the outgoing HTTP request with http.NewRequestWithContext(ctx, "POST", baseUrl+"/chat/completions", body). If that call fails, it returns "error creating request: %w". Since the body is a valid bytes.Reader, failure almost always means the URL failed to parse — i.e. baseUrl is empty or malformed — or the context was already invalid.

Source

Thrown at app/server/model/client.go:340

	var err error
	if openaiReq != nil {
		jsonBody, err = json.Marshal(openaiReq)
	} else {
		jsonBody, err = json.Marshal(extendedReq)
	}
	if err != nil {
		return nil, fmt.Errorf("error marshaling request: %w", err)
	}

	// log.Println("request jsonBody", string(jsonBody))

	// Create new request
	baseUrl := baseModelConfig.BaseUrl
	url := baseUrl + "/chat/completions"

	req, err := http.NewRequestWithContext(ctx, "POST", url, bytes.NewReader(jsonBody))
	if err != nil {
		return nil, fmt.Errorf("error creating request: %w", err)
	}

	// Set required headers for streaming
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("Accept", "text/event-stream")
	req.Header.Set("Cache-Control", "no-cache")
	req.Header.Set("Connection", "keep-alive")

	// some providers send api key in the body, some in the header
	// some use other auth methods and so don't have a simple api key
	if client.ApiKey != "" {
		req.Header.Set("Authorization", "Bearer "+client.ApiKey)
	}
	if client.OpenAIOrgId != "" {
		req.Header.Set("OpenAI-Organization", client.OpenAIOrgId)
	}

	addOpenRouterHeaders(req)

View on GitHub (pinned to e2d772072e)

Solutions

  1. Log/inspect baseModelConfig.BaseUrl for this provider — it is usually empty or malformed; fix the provider base-URL env var (e.g. AZURE_API_BASE, OPENAI_API_BASE).
  2. Ensure BaseUrl includes the scheme (https://...) and has no whitespace or quotes.
  3. Add a startup config check that every provider's BaseUrl parses with url.Parse before serving traffic.
  4. Sanitize: strings.TrimSpace the env value before assigning it to BaseUrl.

Example fix

// before
AZURE_API_BASE=" https://myres.openai.azure.com "  // leading/trailing space -> url parse error
// after
AZURE_API_BASE=https://myres.openai.azure.com
// defensively in code:
url := strings.TrimSpace(baseModelConfig.BaseUrl) + "/chat/completions"
Defensive patterns

Strategy: validation

Validate before calling

// validate the provider base URL before calling the API
u, err := url.Parse(strings.TrimSpace(os.Getenv("AZURE_API_BASE")))
if err != nil || u.Scheme == "" || u.Host == "" {
    return fmt.Errorf("provider base URL missing or invalid: %q", os.Getenv("AZURE_API_BASE"))
}

Type guard

func isValidBaseURL(s string) bool {
    u, err := url.Parse(strings.TrimSpace(s))
    return err == nil && (u.Scheme == "http" || u.Scheme == "https") && u.Host != ""
}

Try / catch

stream, err := client.CreateChatCompletionStream(ctx, req)
if err != nil && strings.Contains(err.Error(), "error creating request") {
    return fmt.Errorf("check the provider BaseUrl env var — it must be an absolute http(s) URL with no whitespace: %w", err)
}

Prevention

When it happens

Trigger: createChatCompletionStreamExtended builds url := baseModelConfig.BaseUrl + "/chat/completions" and http.NewRequestWithContext fails because BaseUrl is empty ("/chat/completions" is a relative URL and http.NewRequest rejects it with http: nil Request.URL), contains spaces/illegal characters, has an unsupported scheme, or ctx is already done.

Common situations: Missing AZURE_API_BASE / provider base URL env var so BaseUrl resolves to empty string; base URL set with a trailing space or embedded quotes in an env file; using an "localhost:8080" value without the http:// scheme; DNS-style typos like "https://api provider.com".

Related errors


AI-assisted analysis of plandex-ai/plandex@e2d772072e (2026-09-05). Data as JSON: /api/errors/74af9220eddaadd9. Report an issue: GitHub.