toeverything/AFFiNE · error · Error

[Table(${tableName})]: There should be only one field marked

Error message

[Table(${tableName})]: There should be only one field marked as primary key. Found [${primaryFields.join(', ')}].

What it means

Schema validator OnlyOnePrimaryKey fires when more than one field in a table definition is marked .primaryKey(). The ORM supports only single-column primary keys; composite keys are rejected at definition time and the message lists every offending field name.

Source

Thrown at packages/common/infra/src/orm/core/validators/schema.ts:24

      if (!Object.values(table).some(field => field.schema.isPrimaryKey)) {
        throw new Error(
          `[Table(${tableName})]: There should be at least one field marked as primary key.`
        );
      }
    },
  },
  OnlyOnePrimaryKey: {
    validate(tableName, table) {
      const primaryFields = [];

      for (const name in table) {
        if (table[name].schema.isPrimaryKey) {
          primaryFields.push(name);
        }
      }

      if (primaryFields.length > 1) {
        throw new Error(
          `[Table(${tableName})]: There should be only one field marked as primary key. Found [${primaryFields.join(', ')}].`
        );
      }
    },
  },
  PrimaryKeyShouldNotBeOptional: {
    validate(tableName, table) {
      for (const name in table) {
        const opts = table[name].schema;
        if (opts.isPrimaryKey && opts.optional && !opts.default) {
          throw new Error(
            `[Table(${tableName})]: Field '${name}' can't be marked primary key and optional with no default value provider at the same time.`
          );
        }
      }
    },
  },
};

View on GitHub (pinned to b4c8548c09)

Solutions

  1. Keep exactly one .primaryKey() (usually a synthetic id) and remove the marker from the other fields.
  2. For join/linking tables, give them a generated id primary key and store the two foreign keys as regular indexed fields.
  3. If you need uniqueness across columns, enforce it at the application layer (lookup before insert) since the ORM won't do composite uniqueness.

Example fix

// before
export const Member = t.table('member', {
  workspaceId: t.string().primaryKey(),
  userId: t.string().primaryKey(),
});

// after
export const Member = t.table('member', {
  id: t.string().primaryKey(),
  workspaceId: t.string(),
  userId: t.string(),
});
Defensive patterns

Strategy: validation

Validate before calling

const pkCount = Object.values(fields).filter(f => f.isPrimaryKey).length;
if (pkCount > 1) throw new Error('composite primary keys are not supported — use a synthetic id');

Try / catch

try { registerTable(MyTable); } catch (e) { if (e instanceof Error && e.message.includes('only one field marked as primary key')) { /* demote extra PK fields to plain indexed fields */ } throw e; }

Prevention

When it happens

Trigger: Marking two columns (e.g. workspaceId and docId) with .primaryKey() to emulate a composite key; pasting a join-table definition from SQL habits where PRIMARY KEY (a, b) is normal.

Common situations: Porting a relational schema with composite keys; trying to enforce uniqueness on a secondary column by making it a primary key instead of adding a uniqueness check.

Related errors


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