router-for-me/CLIProxyAPI · error
Realtime client secrets require an SDP or JSON call request
Error message
Realtime client secrets require an SDP or JSON call request
What it means
Defensive guard in hostHTTPClient.doHTTP: the method is invoked on a nil client or a client whose host pointer is nil. In practice this means the HTTP bridge object was used after being torn down or was constructed outside the host.
Source
Thrown at internal/client/codex/live/live.go:561
contentType = "application/json"
}
return body, contentType, model, nil
}
func applyClientSecretCallSession(body []byte, contentType, model string, session json.RawMessage) ([]byte, string, string, error) {
if len(session) == 0 {
return body, contentType, model, nil
}
mediaType, _, errMediaType := mime.ParseMediaType(contentType)
if errMediaType == nil && (strings.EqualFold(mediaType, "application/sdp") || strings.EqualFold(mediaType, "text/plain")) {
encoded, errEncode := encodeCallRequest(string(body), session)
if errEncode != nil {
return nil, "", "", errEncode
}
return encoded, "application/json", modelFromJSON(session), nil
}
if errMediaType != nil || !strings.EqualFold(mediaType, "application/json") {
return nil, "", "", errors.New("Realtime client secrets require an SDP or JSON call request")
}
var payload map[string]json.RawMessage
if errUnmarshal := json.Unmarshal(body, &payload); errUnmarshal != nil {
return nil, "", "", fmt.Errorf("failed to decode Realtime call request: %w", errUnmarshal)
}
payload["session"] = append(json.RawMessage(nil), session...)
encoded, errMarshal := json.Marshal(payload)
if errMarshal != nil {
return nil, "", "", fmt.Errorf("failed to encode Realtime call request: %w", errMarshal)
}
return encoded, "application/json", modelFromJSON(session), nil
}
func rewriteCallRequestModel(body []byte, contentType, model string) ([]byte, string, error) {
upstreamModel := codexRealtimeModel(model)
mediaType, _, errMediaType := mime.ParseMediaType(contentType)
if errMediaType != nil || !strings.EqualFold(mediaType, "application/json") || len(bytes.TrimSpace(body)) == 0 {
return body, upstreamModel, nilView on GitHub (pinned to 78f0c4079e)
Solutions
- Obtain the HTTP client from the live host API during a callback, not from a cached global.
- Do not issue host HTTP calls after host shutdown has begun.
- In tests, construct the bridge through the Host, not as a zero value.
Defensive patterns
Strategy: type-guard
Type guard
// Go: guard before use
if c == nil || c.host == nil {
return errors.New("host http client is unavailable")
} Try / catch
resp, err := client.Do(ctx, req)
if err != nil && strings.Contains(err.Error(), "host http client is unavailable") {
// lifecycle bug: client used outside the host's lifetime — re-acquire from the live host API
} Prevention
- Fetch the HTTP client from the live host API per callback instead of caching it globally.
- Never use host bridges after shutdown begins.
- In tests, obtain the client from a constructed Host.
When it happens
Trigger: Calling Do/DoStream on a zero-value hostHTTPClient, or retaining the bridge after the Host was shut down and its back-references dropped.
Common situations: Embedders stashing the plugin-side HTTP client beyond the plugin/host lifecycle; races during shutdown; test code constructing the bridge directly.
Related errors
- Codex live call request requires an SDP offer
- Codex Alpha Search API key base URL unavailable
- Codex live request body too large
- Codex live multipart boundary is missing
- 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/a7ded811bba2e749.
Report an issue: GitHub.