hcengineering/platform · warning

request hang found

Error message

request hang found

What it means

For each active session request, the session tick checks how long it has been running; every hangRequestTimeoutSeconds it logs this warning with elapsed seconds, workspace, pending request count, user, and truncated request params. It identifies server-side requests (RPC) that never completed, typically because the client disconnected mid-request or the operation is genuinely stuck.

Source

Thrown at foundations/server/packages/server/src/sessionManager.ts:400

            this.ctx.error('failed to close', err)
          })
          continue
        }
        if (
          lastRequestDiff + (1 / 10) * lastRequestDiff > this.timeouts.pingTimeout &&
          now - s.session.lastPing > this.timeouts.pingTimeout
        ) {
          // We need to check state and close socket if it broken
          // And ping other wize
          s.session.lastPing = now
          if (s.socket.checkState()) {
            void s.socket.send(this.ticksContext, { result: pingConst }, s.session.binaryMode, s.session.useCompression)
          }
        }
        for (const r of s.session.requests.values()) {
          const sec = Math.round((now - r.start) / 1000)
          if (sec > 0 && sec % hangRequestTimeoutSeconds === 0) {
            this.ctx.warn('request hang found', {
              sec,
              wsId,
              total: s.session.requests.size,
              user: s.session.getUser(),
              params: cutObjectArray(r.params)
            })
          }
        }
      }
    }
  }

  createSession (token: Token, workspace: WorkspaceIds, info: LoginInfoWithWorkspaces): Session {
    let primarySocialId: PersonId
    let role: AccountRole = info.workspaces[workspace.uuid]?.role ?? AccountRole.User
    switch (info.account) {
      case systemAccountUuid:
        primarySocialId = core.account.System

View on GitHub (pinned to 63e28dc964)

Solutions

  1. Identify the stuck request via the logged params/wsId and profile the corresponding handler
  2. Optimize long-running queries or add streaming/pagination so they finish under the timeout
  3. Check downstream dependencies (datalake, DB, Kafka) for latency or deadlock
  4. Raise hangRequestTimeoutSeconds only if requests legitimately take longer; repeated warnings mean a real leak

Example fix

// before
await findAll(ctx, clazz, { limit: 1000000 })
// after
await findAll(ctx, clazz, { limit: 1000, ...page }) // paginate under timeout
Defensive patterns

Strategy: try-catch

Validate before calling

const started = Date.now()
const result = await withTimeout(clientRequest, hangRequestTimeoutSeconds * 1000)
function withTimeout<T>(p: Promise<T>, ms: number): Promise<T> {
  return Promise.race([p, new Promise<T>((_, rej) => setTimeout(() => rej(new Error('client-side request timeout')), ms))])
}

Type guard

function isLongRunning(r: { start: number }, thresholdSec: number): boolean {
  return (Date.now() - r.start) / 1000 > thresholdSec
}

Try / catch

try {
  await request
} catch (err) {
  if (isTimeoutError(err)) {
    logger.warn('request exceeded hang threshold', { elapsed: Date.now() - start })
    // cancel and retry with smaller scope/pagination
  } else throw err
}

Prevention

When it happens

Trigger: handleSessionTick iterates session.requests and finds a request whose start time exceeds a multiple of hangRequestTimeoutSeconds — long-running queries, deadlocks, or requests belonging to hung clients that will never read the response.

Common situations: Heavy queries over large workspaces exceeding the timeout; awaited downstream calls (storage, kafka, DB) blocked; clients disconnected while request still executing; repeated logs for the same request indicate a truly stuck operation.

Related errors


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