multica-ai/multica · error · ErrInvalidBaseURL
%w: %s
Error message
%w: %s
What it means
Cloudruntime Client.doInner rejects the configured base URL: url.Parse failed or the parsed URL lacks a scheme/host, and the error wraps the sentinel ErrInvalidBaseURL. The '%w: %s' format preserves errors.Is(err, ErrInvalidBaseURL) while showing the offending value, so callers can distinguish misconfiguration from transport failures.
Source
Thrown at server/internal/cloudruntime/client.go:129
func (c *Client) Do(ctx context.Context, req Request) (*Response, error) {
if c == nil || c.baseURL == "" {
return nil, ErrDisabled
}
op := inferCloudRuntimeOp(req.Op, req.Method, req.Path)
start := time.Now()
resp, err := c.doInner(ctx, req)
if c.recorder != nil {
status := requestStatusBucket(resp, err)
c.recorder.RecordCloudRuntimeRequest(op, status, time.Since(start).Seconds())
}
return resp, err
}
func (c *Client) doInner(ctx context.Context, req Request) (*Response, error) {
base, err := url.Parse(c.baseURL)
if err != nil || base.Scheme == "" || base.Host == "" {
return nil, fmt.Errorf("%w: %s", ErrInvalidBaseURL, c.baseURL)
}
if !strings.HasPrefix(req.Path, "/") {
return nil, fmt.Errorf("cloud runtime path must start with /: %s", req.Path)
}
u := *base
u.Path = strings.TrimRight(base.Path, "/") + req.Path
u.RawQuery = req.Query.Encode()
var body io.Reader
if len(req.Body) > 0 {
body = bytes.NewReader(req.Body)
}
httpReq, err := http.NewRequestWithContext(ctx, req.Method, u.String(), body)
if err != nil {
return nil, err
}
httpReq.Header.Set("Accept", "application/json")View on GitHub (pinned to 2c0912b6ec)
Solutions
- Set a complete base URL including scheme and host, e.g. 'https://runtime.example.com'
- Validate the URL once at startup (url.Parse + scheme/host check) and fail configuration, not per-request
- Check where the client's baseURL comes from (env/config flag) and confirm the value actually reaches the constructor
Example fix
// before
base, err := url.Parse(c.baseURL)
if err != nil || base.Scheme == "" || base.Host == "" {
return nil, fmt.Errorf("%w: %s", ErrInvalidBaseURL, c.baseURL)
}
// after (caller side): validate at construction so requests never carry a bad URL
if _, err := url.Parse(baseURL); err != nil {
return nil, fmt.Errorf("base URL: %w", err)
}
u, _ := url.Parse(baseURL)
if u.Scheme == "" || u.Host == "" {
return nil, fmt.Errorf("base URL %q must include scheme and host", baseURL)
} Defensive patterns
Strategy: validation
Validate before calling
// Validate before constructing/using the client.
func ValidBaseURL(raw string) bool {
u, err := url.Parse(strings.TrimSpace(raw))
return err == nil && u.Scheme != "" && u.Host != ""
}
if !ValidBaseURL(cfg.CloudRuntimeURL) {
return fmt.Errorf("cloud runtime URL %q must include scheme and host", cfg.CloudRuntimeURL)
} Try / catch
Check errors.Is(err, cloudruntime.ErrInvalidBaseURL) and route to configuration-error handling (fail fast at startup) rather than generic request-failure handling.
Prevention
- Validate URLs once at config load, not per request
- Source base URLs from typed config, never raw env strings
- Unit-test the client with an httptest server so malformed URLs never reach production
When it happens
Trigger: Constructing or calling the cloud runtime client with baseURL set to '', 'localhost:8080' (no scheme), 'http://' (no host), or a value with embedded whitespace/control characters. Also a baseURL sourced from an env var or server config that was never validated.
Common situations: MULTICA_* env var typos, config files with empty/placeholder URLs ('TODO'), URLs copied with a leading space, or a URL built by string concatenation that dropped the scheme.
Related errors
- value must be a URL string
- value must be an http(s) URL
- config must be a JSON object
- config must not be empty
- entry must be a JSON object
AI-assisted analysis of multica-ai/multica@2c0912b6ec (2026-08-15).
Data as JSON: /api/errors/d25da9f586da05d8.
Report an issue: GitHub.