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

  1. Normalize and validate the URL in the plugin before calling: url.Parse, require a non-empty scheme and host.
  2. Prepend "https://" when the scheme is missing.
  3. 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

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


AI-assisted analysis of router-for-me/CLIProxyAPI@78f0c4079e (2026-08-15). Data as JSON: /api/errors/13a59722ab392a68. Report an issue: GitHub.