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

  1. Guard your init logic: only call serveAgent once per endpoint URL
  2. Check whether the endpoint is already served (track your own set of served URLs) before calling
  3. Use a different port/URL for the second agent instance
  4. 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

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


AI-assisted analysis of hcengineering/platform@63e28dc964 (2026-08-29). Data as JSON: /api/errors/1d5c0fc54c896ec1. Report an issue: GitHub.