gastownhall/beads · error
create request: %w
Error message
create request: %w
What it means
http.NewRequestWithContext failed while constructing the outgoing Notion HTTP request. With a fixed method and URL scheme this is rare, and almost always means the assembled requestURL is malformed (unparseable URL) or the context is already cancelled/invalid. The error is wrapped so the net/http cause is preserved.
Source
Thrown at internal/notion/client.go:271
httpClient = &http.Client{Timeout: DefaultTimeout}
}
var bodyReader io.Reader
if requestBody != nil {
payload, err := json.Marshal(requestBody)
if err != nil {
return nil, fmt.Errorf("marshal request body: %w", err)
}
bodyReader = bytes.NewReader(payload)
}
requestURL := path
if !strings.HasPrefix(requestURL, "http://") && !strings.HasPrefix(requestURL, "https://") {
requestURL = strings.TrimSuffix(c.BaseURL, "/") + path
}
req, err := http.NewRequestWithContext(ctx, method, requestURL, bodyReader)
if err != nil {
return nil, fmt.Errorf("create request: %w", err)
}
req.Header.Set("Authorization", "Bearer "+c.Token)
req.Header.Set("Notion-Version", c.NotionVersion)
req.Header.Set("Accept", "application/json")
if requestBody != nil {
req.Header.Set("Content-Type", "application/json")
}
resp, err := httpClient.Do(req) //nolint:gosec // G704: URL is constructed from configured Notion API base, not user input
if err != nil {
return nil, fmt.Errorf("request failed: %w", err)
}
defer func() { _ = resp.Body.Close() }()
body, err := io.ReadAll(io.LimitReader(resp.Body, maxResponseBytes))
if err != nil {
return nil, fmt.Errorf("read response: %w", err)
}View on GitHub (pinned to 71377f2769)
Solutions
- Inspect the wrapped error for 'parse ...' to see the malformed URL, then fix BaseURL (must be a valid absolute URL like https://api.notion.com/v1).
- Trim whitespace/newlines from the configured base URL before constructing the client.
- Leave BaseURL at its default unless you intentionally use a proxy/gateway.
- Test URL assembly: u, err := url.Parse(strings.TrimSuffix(baseURL, "/") + path); validate err at startup.
Example fix
// before
client := notion.NewClientWithBaseURL("https://api.notion.com/v1
") // invalid URL
// after
baseURL := strings.TrimSpace(cfg.NotionBaseURL)
u, err := url.Parse(baseURL)
if err != nil || u.Scheme == "" {
return fmt.Errorf("invalid notion base URL: %w", err)
}
client := notion.NewClientWithBaseURL(baseURL) Defensive patterns
Strategy: validation
Validate before calling
u, err := url.Parse(strings.TrimSuffix(baseURL, "/") + path)
if err != nil {
return fmt.Errorf("invalid notion URL: %w", err)
} Try / catch
if err != nil && strings.Contains(err.Error(), "create request") {
log.Printf("check NOTION_BASE_URL / request path: %v", err)
} Prevention
- Trim whitespace/newlines from BaseURL at config load time.
- Validate BaseURL with url.Parse at startup; require an https scheme.
- Keep BaseURL at the library default unless a proxy is required.
When it happens
Trigger: c.BaseURL misconfigured so the concatenated URL is invalid (e.g. BaseURL containing spaces or garbage); calling a wrapper with a path containing unescaped characters; passing an already-cancelled context is not it - that fails later - but an invalid URL/control characters in method or URL will trigger this.
Common situations: Config file with NOTION_BASE_URL pointing to a wrong, typo'd, or containing-invalid-characters value (spaces, newline); overriding BaseURL to a proxy URL with stray characters; tests constructing Client{BaseURL: "://bad"}.
Related errors
- failed to create request: %w
- read response: %w
- failed to list projects: %w
- pypi api returned status %d
- add remote %s: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/4d2118b10c26ca04.
Report an issue: GitHub.