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

  1. Complete the plugin's function table: set both call and free_buffer in cliproxy_plugin_init.
  2. Prefer deriving the plugin from the official SDK skeleton so table wiring stays correct.
  3. 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

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


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