hcengineering/platform · error

Router is not bound to a port

Error message

Router is not bound to a port

What it means

backrpc Server.getPort() parses the port from router.lastEndpoint via the regex /:(\d+)$/. If the endpoint string doesn't end in `:<port>` (e.g. a Unix socket path, named pipe, or port-0 style endpoint), parseInt yields undefined and the server throws because it cannot determine a TCP port. The endpoint is bound, but not to a numeric port.

Source

Thrown at foundations/net/packages/backrpc/src/server.ts:125

  private handleClose (clientRecordId: ClientT, clientId: string, timeout: boolean): void {
    void this.handlers.closeHandler?.(clientRecordId, timeout).catch((err) => {
      console.error('Error in handleTimeout', err)
    })
    this.revClientMapping.delete(clientId)
    this.clientMapping.delete(clientRecordId)
  }

  async getPort (): Promise<number> {
    await this.bound
    const reqEndpoint = this.router.lastEndpoint
    if (reqEndpoint === null) {
      throw new Error('Router is not bound to an endpoint')
    }

    const portMatch = reqEndpoint.match(/:(\d+)$/)
    const port = portMatch != null ? parseInt(portMatch[1]) : undefined
    if (port === undefined) {
      throw new Error('Router is not bound to a port')
    }
    return port
  }

  private sendPromise: Promise<void> | undefined

  async doSend (msg: any[]): Promise<void> {
    while (this.sendPromise !== undefined) {
      await this.sendPromise
    }
    this.sendPromise = this.router.send(msg)
    try {
      await this.sendPromise
    } catch (err: any) {
      console.error('Failed to send message', err)
    }
    this.sendPromise = undefined
  }

View on GitHub (pinned to 63e28dc964)

Solutions

  1. Bind the router to a TCP endpoint with an explicit numeric port (e.g. host:port form ending in :8080).
  2. If using a Unix socket/named pipe, read the socket path from the endpoint instead of calling getPort().
  3. Check the lastEndpoint string format your transport produces and match the /:(\d+)$/ expectation.
  4. Specify a concrete port in configuration rather than an ephemeral or implicit one.

Example fix

// before: bound to a unix socket, getPort() can't parse a port
const server = new Server({ endpoint: 'unix:/tmp/backrpc.sock' });
const port = await server.getPort(); // throws
// after: bind to TCP with an explicit port
const server = new Server({ endpoint: '127.0.0.1:8080' });
const port = await server.getPort(); // 8080
Defensive patterns

Strategy: type-guard

Validate before calling

function isTcpEndpoint(ep) { return typeof ep === 'string' && /:(\d+)$/.test(ep); }
// only call getPort() when the bound endpoint is TCP
if (isTcpEndpoint(server.router.lastEndpoint)) { await server.getPort(); }

Type guard

function hasTcpEndpoint(server) {
  const ep = server.router?.lastEndpoint;
  return typeof ep === 'string' && /:(\d+)$/.test(ep);
}

Try / catch

try {
  const port = await server.getPort();
} catch (e) {
  if (e.message === 'Router is not bound to a port') {
    // endpoint exists but is not TCP (e.g. unix socket) — use the path instead
    const socketPath = server.router.lastEndpoint;
    console.log('Non-TCP endpoint:', socketPath);
  } else throw e;
}

Prevention

When it happens

Trigger: Router bound to a non-TCP endpoint (Unix domain socket, named pipe) or an endpoint string without a trailing `:digits`, then calling getPort().

Common situations: Configuring the transport with a unix:/path-to-socket endpoint and then asking for a TCP port; binding to port 0 or a hostname-only endpoint; transport writing lastEndpoint in a format the regex doesn't match.

Related errors


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