router-for-me/CLIProxyAPI · error
Codex live media relay capacity exhausted
Error message
Codex live media relay capacity exhausted
What it means
Post-init validation: the function table the plugin filled in is missing mandatory entries (call or free_buffer is NULL). Even though init returned success and the ABI matched, the host cannot operate a plugin without both callbacks, so it shuts it down. Indicates a broken or hand-rolled plugin implementation.
Source
Thrown at internal/client/codex/live/media.go:281
}
if errContext := ctx.Err(); errContext != nil {
return nil, "", errContext
}
builtProxyDialer, proxyMode, errProxy := proxyutil.BuildDialer(route.proxyURL)
if errProxy != nil {
return nil, "", fmt.Errorf("configure Codex live remote TCP proxy: %w", errProxy)
}
proxied := proxyMode == proxyutil.ModeProxy
var proxyDialer proxy.ContextDialer
if proxied {
contextDialer, ok := builtProxyDialer.(proxy.ContextDialer)
if !ok {
return nil, "", errors.New("Codex live remote TCP proxy does not support cancellation")
}
proxyDialer = contextDialer
}
if !r.limiter.acquire() {
return nil, "", errors.New("Codex live media relay capacity exhausted")
}
releaseSlot := r.limiter.release
downstream, errDownstream := r.downstreamAPI.NewPeerConnection(r.configuration)
if errDownstream != nil {
releaseSlot()
return nil, "", fmt.Errorf("create downstream PeerConnection: %w", errDownstream)
}
upstreamAPI := r.upstreamAPI
upstreamConfiguration := r.configuration
if proxied {
upstreamAPI = r.proxyUpstreamAPI
upstreamConfiguration.ICEServers = nil
}
upstream, errUpstream := upstreamAPI.NewPeerConnection(upstreamConfiguration)
if errUpstream != nil {
releaseSlot()
if errClose := downstream.Close(); errClose != nil {
log.WithError(errClose).Debug("codex live media: close downstream PeerConnection after setup error")View on GitHub (pinned to 78f0c4079e)
Solutions
- Complete the plugin's function table: set both call and free_buffer in cliproxy_plugin_init.
- Prefer deriving the plugin from the official SDK skeleton so table wiring stays correct.
- Rebuild against the host's exact SDK version.
Example fix
// plugin init: fill every required slot
//export cliproxy_plugin_init
func cliproxy_plugin_init(api *C.cliproxy_plugin_api) C.int {
api.abi_version = C.uint32_t(hostABI) // matches pluginHostABIVersion
api.call = (C.cliproxy_call_fn)(C.pluginCall)
api.free_buffer = (C.cliproxy_free_buffer_fn)(C.pluginFreeBuffer) // was missing
return 0
} Defensive patterns
Strategy: validation
Validate before calling
// plugin-side unit test: assert the table is complete after init
initTable(t)
if table.call == nil || table.free_buffer == nil {
t.Fatal("plugin function table is incomplete")
} Prevention
- Derive plugins from the SDK skeleton so the function table is filled correctly.
- Add a startup self-check that all required table slots are non-nil before returning from init.
- Rebuild against the host's exact SDK version.
When it happens
Trigger: A plugin that leaves required table slots nil — partially implemented skeleton, init that zeroes the struct, or a plugin built against a dev SDK revision where the table contract differed.
Common situations: Custom plugins written from scratch that fill only the fields they use; refactoring that drops table assignment; plugin author assuming fields are optional.
Related errors
- Codex live remote TCP proxy does not support cancellation
- Codex live media relay requires an SDP or JSON call request
- Codex live response requires an SDP answer
- auth file not found
- count must be a positive integer
AI-assisted analysis of router-for-me/CLIProxyAPI@78f0c4079e (2026-08-15).
Data as JSON: /api/errors/ac498d31fed7f034.
Report an issue: GitHub.