toeverything/AFFiNE · error · Error

main peer is readonly

Error message

main peer is readonly

What it means

BlobEngine.set() refuses every write when this.main.readonly is true — the primary blob peer was constructed read-only (for example the collection/blob engine was opened without write intent or on read-only storage). All blob writes must go to a writable main peer, so this error is an access-mode problem, not a data problem.

Source

Thrown at blocksuite/framework/sync/src/blob/engine.ts:65

    const blobIdSet = new Set<string>();

    for (const source of this.sources) {
      const blobs = await source.list();
      for (const blob of blobs) {
        blobIdSet.add(blob);
      }
    }

    return Array.from(blobIdSet);
  }

  async set(value: Blob): Promise<string>;

  async set(key: string, value: Blob): Promise<string>;

  async set(valueOrKey: string | Blob, _value?: Blob) {
    if (this.main.readonly) {
      throw new Error('main peer is readonly');
    }

    const key =
      typeof valueOrKey === 'string'
        ? valueOrKey
        : await sha(await valueOrKey.arrayBuffer());
    const value = typeof valueOrKey === 'string' ? _value : valueOrKey;

    if (!value) {
      throw new Error('value is empty');
    }

    // await upload to the main peer
    await this.main.set(key, value);

    // uploads to other peers in the background
    Promise.allSettled(
      this.shadows

View on GitHub (pinned to b4c8548c09)

Solutions

  1. Open the collection/blob peer with write access before uploading blobs.
  2. Guard with if (engine.main.readonly) before calling set and surface a permission error.
  3. Route writes to a writable engine instance rather than the read-only one.

Example fix

// before
await engine.set(blob);

// after
if (engine.main.readonly) {
  throw new Error('blob storage is read-only; open with write access to upload');
}
await engine.set(blob);
Defensive patterns

Strategy: validation

Validate before calling

if (engine.main.readonly) {
  throw new Error('blob storage opened read-only; cannot write blobs');
}
await engine.set(blob);

Type guard

const isWritableBlobEngine = (engine: BlobEngine): boolean =>
  !engine.main.readonly;

Try / catch

try {
  await engine.set(blob);
} catch (e) {
  if (e instanceof Error && e.message === 'main peer is readonly') {
    // open a writable collection/engine instance, then retry
  } else throw e;
}

Prevention

When it happens

Trigger: engine.set(key, blob) or engine.set(blob) while the main blob peer was created with readonly: true; referencing a doc/workspace opened read-only (no write permission); test setups mounting blob storage in read-only mode.

Common situations: Opening shared or published docs read-only and then attempting an upload; permission downgrade between open and write; readonly fixture storages in tests.

Related errors


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