hcengineering/platform · error
Agent server already running at ${endpointUrl}
Error message
Agent server already running at ${endpointUrl} What it means
serveAgent starts a local agent RPC server bound to endpointUrl, but first checks the client's servers list and throws if a server is already registered on that exact URL. Prevents double-binding the same host:port endpoint within one NetworkClientImpl instance.
Source
Thrown at foundations/net/packages/client/src/index.ts:57
factory: Record<ContainerKind, ContainerFactory>,
statelessContainers?: StatelessContainersFactory
) => Promise<void>
}
class NetworkClientWithAgents extends NetworkClientImpl implements ClientWithAgents {
servers: [string, NetworkAgentServer][] = []
constructor (host: string, port: number, aliveTimeout?: number) {
super(host, port, new TickManagerImpl(timeouts.pingInterval * 2), aliveTimeout)
}
async serveAgent (
endpointUrl: string,
factory: Record<ContainerKind, ContainerFactory>,
statelessContainers?: StatelessContainersFactory
): Promise<void> {
if (this.servers.find((s) => s[0] === endpointUrl) != null) {
throw new Error(`Agent server already running at ${endpointUrl}`)
}
const agent = new AgentImpl(uuidv4() as AgentUuid, factory)
const [host, portStr] = endpointUrl.split(':')
const port = portStr != null ? parseInt(portStr, 10) : 3738
const server = new NetworkAgentServer(this.tickMgr, host, '*', port)
this.servers.push([endpointUrl, server])
await server.start(agent)
// Add stateless containers if provided
if (statelessContainers != null) {
// Get the agent endpoint after server starts - it should be initialized
const agentEndpoint = agent.endpoint
if (agentEndpoint === undefined) {
throw new Error('Agent endpoint not initialized after server start')
}
View on GitHub (pinned to 63e28dc964)
Solutions
- Guard your init logic: only call serveAgent once per endpoint URL
- Check whether the endpoint is already served (track your own set of served URLs) before calling
- Use a different port/URL for the second agent instance
- If restart is intended, create a fresh client or tear down the existing server first
Example fix
// before
await client.serveAgent('localhost:3738', factories) // called on every retry
// after
if (!servedEndpoints.has('localhost:3738')) {
await client.serveAgent('localhost:3738', factories)
servedEndpoints.add('localhost:3738')
} Defensive patterns
Strategy: validation
Validate before calling
const servedUrls = new Set<string>()
function canServe(url: string): boolean {
return !servedUrls.has(url)
} Type guard
function isUrlServed(url: string, servers: Array<[string, unknown]>): boolean {
return servers.some(([u]) => u === url)
} Try / catch
try {
await client.serveAgent(url, factories)
} catch (e) {
if (e instanceof Error && e.message.startsWith('Agent server already running')) {
// already initialized; skip
} else { throw e }
} Prevention
- Make bootstrap/HA init idempotent with a served-URL set
- Use unique ports per agent instance
- Don't call serveAgent inside retry loops without guards
- Track client instance lifetime to avoid double init
When it happens
Trigger: Calling client.serveAgent(endpointUrl, ...) twice with the same 'host:port' string on the same client instance, e.g. re-invoking an init routine or registering the same endpoint in createHAAgent/registerBenchmark setup.
Common situations: Idempotency guard missing in bootstrap code that runs on reconnect; HA setup scripts calling serveAgent for the same endpoint on every retry; benchmark harness re-registering agents.
Related errors
- Message id is required
- Hierarchy is not defined
- Model is not defined
- Router is not bound to an endpoint
- Router is not bound to a port
AI-assisted analysis of hcengineering/platform@63e28dc964 (2026-08-29).
Data as JSON: /api/errors/1d5c0fc54c896ec1.
Report an issue: GitHub.