# Error reference

**URL:** https://heroiclabs.com/docs/nakama/server-framework/errors/
**Summary:** Reference for Nakama gRPC status codes, their HTTP mappings, common transport errors, and server framework runtime error values.
**Keywords:** nakama errors, grpc status codes, http status codes, runtime errors, context canceled, context deadline exceeded, storage write rejected, version check failed, heartbeat failure, could not authenticate, match not found, debugging nakama

---


# Error reference

This page is a reference for the errors you may encounter when working with Nakama, so you can identify what an error means, whether it's expected, and what to check next.

Nakama exposes its API over both gRPC and HTTP. Clients receive errors from two layers:

- **Transport and networking** errors from the gRPC/HTTP layer, such as a canceled request or a timed-out connection.
- **Application** errors from the server, carrying a gRPC status code and a human-readable message.

Server framework code (Go, TypeScript, and Lua modules) also returns a set of predefined **runtime error values**, listed at the end of this page.

When you're debugging, the gRPC status code is the stable signal to branch on, but the detail you need is often in the server log rather than the client response. Several errors below return a generic message to the client while recording the specific reason in the log.

## gRPC status codes and HTTP mappings

Every Nakama API error carries a gRPC status code. When a request arrives over HTTP, Nakama maps that code to an HTTP status code. The mapping is the gRPC-gateway default and is stable across Nakama releases.

{{< table name="nakama.server-framework.errors.grpc-http-status" >}}

The status code tells you the category of problem. The codes you see most often from application logic are `InvalidArgument` (a malformed or missing field in your request), `NotFound` (the requested resource doesn't exist), and `Internal` (an unexpected server-side failure).

## Per-endpoint error messages

Alongside the status code, most API errors carry a human-readable message describing what specifically went wrong. A bad pagination value, for example, returns `Invalid limit - limit must be between 1 and 100.`

These messages are defined per endpoint rather than centrally. They live in the `api_*.go` files of the Nakama server source, such as `server/api_storage.go` and `server/api_account.go`, and there are several hundred of them across the API. Because each call site defines its own wording, the same category of problem can be phrased differently by different endpoints.

Treat these messages as diagnostic text for people, not as a stable API contract. Branch on the gRPC status code instead, which is stable across releases. To trace a message back to its origin, search the `server/api_*.go` files for the message text.

Some operations don't expose a distinct status code for every outcome. When a client joins a match that no longer exists, for example, the reliable signal is the `match not found` message rather than a dedicated code. Where an operation lacks a specific code for a case you need to detect, match on the documented message and treat the status code as the coarse category.

## Common transport and networking errors

These errors come from the network or the gRPC layer rather than from Nakama's application logic. Many are expected under normal operating conditions and don't indicate a bug in your integration or in the server.

### Context canceled

The `context canceled` error (gRPC `Canceled`, code 1) means the caller ended the request before it completed. This is one of the most common errors, and it's usually expected: a client closed the connection, navigated away, or canceled the operation while the request was in flight. Over gRPC the full text is `rpc error: code = Canceled desc = context canceled`.

A frequent and benign form is a storage read logged as `Could not read storage objects.` with `"error": "context canceled"`. This means the client disconnected before its database query returned. It's safe to ignore unless it coincides with database performance problems.

**What to check**: confirm the affected requests are ones a client would abandon, such as a screen the player navigated away from or a request behind a flaky connection. Investigate only when cancellation hits requests that should always run to completion, or when you see a sustained spike, which points to database pressure or a client that cancels too aggressively.

### Context deadline exceeded

The `context deadline exceeded` error (gRPC `DeadlineExceeded`, code 4) means an operation ran longer than its allotted timeout. Like context cancellation, it's common and often expected.

A frequent source is an outbound HTTP call from your own runtime code to an external service, such as Satori, an in-app purchase validation endpoint, or a third-party API. These surface as `context deadline exceeded (Client.Timeout exceeded while awaiting headers)`, which means your HTTP client's own timeout elapsed while waiting on the other service. The fix is usually to raise that client's timeout, not a Nakama setting.

**What to check**: identify which operation is timing out. If it's an outbound call from your module, raise that HTTP client's timeout and check the external service's latency. If it's a database operation, check query duration and load such as IOPS and hot rows. Tune Nakama timeouts only once you've ruled out a slow dependency.

### Network I/O timeout

An I/O timeout (for example, `read tcp ... i/o timeout`) means a network read or write didn't complete in time. This is most often caused by an unreliable client connection (a device on a poor mobile network, for example) rather than a problem on the server side.

Treat isolated I/O timeouts as a symptom of network conditions. Investigate only if they're widespread across many clients at once, which can indicate a server or infrastructure issue.

### SSL handshake failure

An SSL or TLS handshake failure means the client and server couldn't establish a secure connection. This is typically a TLS configuration or connectivity issue between the two parties, such as a certificate problem, a protocol mismatch, or a proxy interfering with the connection. It isn't an application error.

The exact message depends on the client platform. Common forms are `The SSL connection could not be established`, `Curl error 60: Cert verify failed`, an `SSL CA certificate error`, and a `TrustFailure` or `Handshake failed` exception. A connection that works on one network but fails on another, for example failing on home broadband but working on mobile data, points to the network path (DNS, IPv6, a proxy, or an ISP) rather than the server.

**What to check**: confirm the certificate chain is trusted on the failing platform, that client and server agree on a TLS version, and whether the failure is specific to one network. A sudden onset across many clients can follow certificate rotation on a dependency such as Satori.

### Storage version rejection

A conditional write whose version check fails returns gRPC `InvalidArgument` (code 3, HTTP 400) with the message `Storage write rejected.` The server framework surfaces it as `ErrStorageRejectedVersion`. This is the expected outcome when another writer updated the object first, and it's how Nakama prevents conflicting concurrent writes.

The server returns the same code and message when it rejects a write for insufficient permissions (`ErrStorageRejectedPermission`), so the response alone doesn't tell you which of the two applied. A conditional delete that fails its version check returns `Storage delete rejected.` with the same code.

When you use Hiro, the same rejection appears in server logs as an `nk.MultiUpdate error` carrying `Storage write rejected - version check failed.`, from the economy, inventory, or achievements systems. It means two operations wrote the same object concurrently, for example an achievement claim and an achievement update running at once, or a client retry replaying a write with a stale version.

**What to check**: look for two writes to the same object overlapping in time. Common sources are concurrent Hiro operations on one user, an offline queue replaying writes on reconnect, and account creation or linking hooks that edit a wallet which already exists. To reduce it, batch updates to the same object into one call, sequence operations that touch the same object, and retry a rejected write with jitter after re-reading the current version.

For how conditional writes work and how to handle a rejected version, see [Conditional writes](/docs/nakama/concepts/storage/collections/#conditional-writes).

## Socket heartbeat disconnects

Nakama keeps realtime socket connections alive with a heartbeat. The server sends a WebSocket ping every `socket.ping_period_ms` (15 seconds by default) and expects a pong back within `socket.pong_wait_ms` (25 seconds by default). If no pong or other message arrives in that window, the server treats the connection as dead and closes it.

The most common cause of an unexpected heartbeat disconnect is a blocked client rather than a network fault. A WebSocket library answers pings automatically, but only while the client keeps servicing its network loop. Long blocking work on that same thread, such as loading assets or running a synchronous scene transition, holds the pong back until the work finishes. If that takes longer than `socket.pong_wait_ms`, the server has already closed the connection.

To avoid this, keep servicing the socket during long operations, move blocking work off the thread that drives the socket, or split it into chunks that yield frequently. Raising `socket.pong_wait_ms` buys headroom but doesn't remove the underlying stall. Always handle the disconnect event and reconnect, because connections also drop for ordinary network reasons.

A client that sends messages regularly doesn't need a ping to prove it's alive. The server skips one when the client sent at least `socket.ping_backoff_threshold` messages (20 by default) during the ping period.

## Social authentication errors

A failed social login returns a generic message to the client rather than the reason the identity provider gave. Authenticating against Google, Apple, Facebook, Game Center, or Steam returns gRPC `Unauthenticated` (HTTP 401) with a message that names only the provider, such as `Could not authenticate Google profile.`

The specific reason comes from the provider, and Nakama writes it to the server log instead of returning it to the client. Typical reasons include an invalid or expired ID token, an unexpected issuer claim, and a failed certificate lookup. Nakama doesn't generate these reasons, so repeated failures usually point to provider-side credentials or configuration rather than to Nakama.

Debug a social authentication failure from the server log entry recorded with the request. The client message alone can't tell you which reason applied.

## Runtime error values

The server framework defines a fixed set of error values in `nakama-common`. Runtime operations return these, so you can match against them in your Go, TypeScript, and Lua modules. The common ones you're likely to act on, such as storage version rejection, are explained in the sections above; the table below is the complete list.

The messages are intentionally terse and often restate the error name, so the value itself rarely tells you what to do next. Match the error rather than its message text (in Go, with `errors.Is`), then follow the **What to do next** column, which explains when each error fires and how to handle it. For the fuller flow, see the concept guide for the system the error belongs to.

{{< table name="nakama.server-framework.errors.runtime-errors" >}}
