toeverything/AFFiNE · error · UserFriendlyError

CONTENT_TOO_LARGE

CONTENT_TOO_LARGE

Error message

Content too large

What it means

HttpConnection.fetch maps any non-ok, non-404 response with status 413 to a UserFriendlyError with code/type/name CONTENT_TOO_LARGE and status 413. This is the generic HTTP layer signal that a request body exceeded a size limit somewhere on the server side — before app-level quota logic even sees it. Blob uploads wrap this further (see error 715), but any other 413 response from the API surfaces here directly.

Solutions

  1. Reduce the request payload — move large binaries to the blob upload API instead of inlining them in GraphQL/JSON bodies.
  2. On self-hosted: raise the reverse proxy body limit (nginx client_max_body_size, etc.) to match your real maximum payload.
  3. Split batched mutations into smaller chunks.
  4. Catch by code: err instanceof UserFriendlyError && err.code === 'CONTENT_TOO_LARGE'.

Example fix

// before
await connection.gql({ query: updateDocMutation, variables: { content: base64Image } });

// after
const { key } = await blobStorage.set({ key: nanoid(), data: bytes, mime });
await connection.gql({ query: updateDocMutation, variables: { content: `affine-blob:///${key}` } });
Defensive patterns

Strategy: validation

Validate before calling

const MAX_BODY = 10 * 1024 * 1024; // keep in sync with proxy client_max_body_size
function approxJsonSize(v: unknown): number { return new Blob([JSON.stringify(v)]).size; }
if (approxJsonSize(variables) > MAX_BODY) throw new Error('payload too large — upload blobs separately');

Type guard

import { UserFriendlyError } from '@affine/error';
const isContentTooLarge = (e: unknown): e is UserFriendlyError =>
  e instanceof UserFriendlyError && e.code === 'CONTENT_TOO_LARGE';

Try / catch

try { await connection.gql({ query, variables }); } catch (e) { if (isContentTooLarge(e)) { /* split the batch or move binaries to blob storage */ } throw e; }

Prevention

When it happens

Trigger: Any POST/PUT through connection.fetch or connection.gql whose body exceeds the server's or an intermediate proxy's body limit and the server answers 413; large GraphQL mutations/queries (e.g. batched operations, big base64 payloads).

Common situations: Sending large inline payloads (base64 images in mutations, huge doc updates) through the GraphQL endpoint behind nginx with default client_max_body_size; gateway/WAF body limits; inconsistent limits between environments (works locally, fails in prod).

Related errors


AI-assisted analysis of toeverything/AFFiNE@b4c8548c09 (2026-08-18). Data as JSON: /api/errors/2a103f6ad15489ba. Report an issue: GitHub.

Appendix: source

Thrown at packages/common/nbstore/src/impls/cloud/http.ts:54

          'x-affine-version': BUILD_CONFIG.appVersion,
        },
      })
      .catch(err => {
        throw new UserFriendlyError({
          status: 504,
          code: 'NETWORK_ERROR',
          type: 'NETWORK_ERROR',
          name: 'NETWORK_ERROR',
          message: `Network error: ${err.message}`,
          stacktrace: err.stack,
        });
      });
    if (timeoutId) {
      clearTimeout(timeoutId);
    }
    if (!res.ok && res.status !== 404) {
      if (res.status === 413) {
        throw new UserFriendlyError({
          status: 413,
          code: 'CONTENT_TOO_LARGE',
          type: 'CONTENT_TOO_LARGE',
          name: 'CONTENT_TOO_LARGE',
          message: 'Content too large',
        });
      } else if (
        res.headers.get('Content-Type')?.startsWith('application/json')
      ) {
        throw UserFriendlyError.fromAny(await res.json());
      } else {
        throw UserFriendlyError.fromAny(await res.text());
      }
    }
    return res;
  };

  readonly fetchArrayBuffer = async (input: string, init?: RequestInit) => {

View on GitHub (pinned to b4c8548c09)