router-for-me/CLIProxyAPI · error
Codex live multipart boundary is missing
Error message
Codex live multipart boundary is missing
What it means
http.NewRequestWithContext failed while turning the plugin-supplied pluginapi.HTTPRequest into a real *http.Request. The method defaults to GET when empty, so failure almost always means an invalid URL (unsupported scheme, control characters, unparsable target) or an invalid method token; the config is still returned alongside the error.
Source
Thrown at internal/client/codex/live/live.go:622
if errMarshal != nil {
return nil, "", fmt.Errorf("failed to encode Realtime model: %w", errMarshal)
}
payload["model"] = encodedModel
changed = true
}
if !changed {
return body, upstreamModel, nil
}
encoded, errMarshal := json.Marshal(payload)
if errMarshal != nil {
return nil, "", fmt.Errorf("failed to encode Realtime call request: %w", errMarshal)
}
return encoded, upstreamModel, nil
}
func multipartCallRequest(body []byte, boundary string) ([]byte, string, string, error) {
if boundary == "" {
return nil, "", "", errors.New("Codex live multipart boundary is missing")
}
reader := multipart.NewReader(bytes.NewReader(body), boundary)
var sdp *string
var session json.RawMessage
model := ""
for {
part, errPart := reader.NextPart()
if errors.Is(errPart, io.EOF) {
break
}
if errPart != nil {
return nil, "", "", fmt.Errorf("failed to parse Codex live multipart body: %w", errPart)
}
partBody, errRead := io.ReadAll(part)
errClose := part.Close()
if errRead != nil {
return nil, "", "", fmt.Errorf("failed to read Codex live multipart field: %w", errRead)View on GitHub (pinned to 78f0c4079e)
Solutions
- Normalize and validate the URL in the plugin before calling: url.Parse, require a non-empty scheme and host.
- Prepend "https://" when the scheme is missing.
- Use url.Values / url.PathEscape for query and path components.
Example fix
// before
req := pluginapi.HTTPRequest{Method: "GET", URL: rawTarget} // rawTarget = "api.example.com/v1/models"
// after
if !strings.Contains(rawTarget, "://") {
rawTarget = "https://" + rawTarget
}
u, err := url.Parse(rawTarget)
if err != nil || u.Scheme == "" || u.Host == "" {
return fmt.Errorf("invalid target URL %q", rawTarget)
}
req := pluginapi.HTTPRequest{Method: "GET", URL: u.String()} Defensive patterns
Strategy: validation
Validate before calling
func validHTTPURL(target string) bool {
if !strings.Contains(target, "://") {
target = "https://" + target
}
u, err := url.Parse(target)
return err == nil && u.Scheme != "" && u.Host != ""
}
if !validHTTPURL(req.URL) {
return fmt.Errorf("invalid target URL %q", req.URL)
} Try / catch
resp, err := http.Do(ctx, req)
if err != nil {
var urlErr *url.Error
if errors.As(err, &urlErr) && strings.Contains(urlErr.Err.Error(), "invalid") {
return fmt.Errorf("malformed request (URL/method): %w", err) // fix input, never retry
}
return err
} Prevention
- Escape all URL components with net/url helpers.
- Always include the scheme.
- Default the method explicitly rather than relying on empty-string coercion downstream.
When it happens
Trigger: Plugin passes req.URL that is empty, lacks a scheme ("api.example.com/v1" instead of "https://..."), contains spaces/control chars, or uses a scheme Go rejects (e.g. "ftp://"-style unsupported by the transport expectations); or req.Method is an invalid HTTP token like "get x".
Common situations: Building URLs from unescaped user input; forgetting the https:// prefix; trailing whitespace in URL config; plugin porting from a client library that tolerates relative URLs.
Related errors
- Codex live multipart body requires an sdp field
- count must be a positive integer
- Codex live request body too large
- Realtime client secrets require an SDP or JSON call request
- Codex live session field must contain valid JSON
AI-assisted analysis of router-for-me/CLIProxyAPI@78f0c4079e (2026-08-15).
Data as JSON: /api/errors/13a59722ab392a68.
Report an issue: GitHub.