twentyhq/twenty · error · Error

upsertRowLevelPermissionPredicates returned no predicates fo

Error message

upsertRowLevelPermissionPredicates returned no predicates for object "${name}"

What it means

configure-partner-rls calls upsertRowLevelPermissionPredicates and expects at least one predicate back; it throws if the returned predicates array is empty. An empty result means the server accepted the upsert call but produced no predicate — a silent rejection (e.g. the field metadata id is invalid, the operand is unsupported, or a server-side guard dropped the predicate) that must not be treated as success.

Source

Thrown at packages/twenty-apps/internal/twenty-partners/src/scripts/configure-partner-rls.ts:489

      input: {
        roleId: partnerRole.id,
        objectMetadataId: info.objectMetadataId,
        predicates: [
          {
            fieldMetadataId: info.partnerUserFieldMetadataId,
            operand: 'IS',
            workspaceMemberFieldMetadataId: workspaceMemberIdFieldId,
          },
        ],
        predicateGroups: [],
      } satisfies UpsertPredicatesInput,
    });

    const predicate =
      data.upsertRowLevelPermissionPredicates.predicates[0];

    if (!predicate) {
      throw new Error(
        `upsertRowLevelPermissionPredicates returned no predicates for object "${name}"`,
      );
    }

    results.push(predicate);
    console.log(
      `[rls:configure] ✓ ${name}: predicate id=${predicate.id} ` +
        `(fieldMetadataId=${predicate.fieldMetadataId}, operand=${predicate.operand})`,
    );
  }

  // Opportunity: (partnerUser IS me) OR (isListed = true) — listed briefs visible to all partners.
  {
    const oppPredicates = await upsertPredicates(
      {
        roleId: partnerRole.id,
        objectMetadataId: opportunityObjectId,
        predicateGroups: [

View on GitHub (pinned to 1f5dd2bbd2)

Solutions

  1. Inspect the full upsert response (data.upsertRowLevelPermissionPredicates) for an errors/null payload — log it before the guard.
  2. Confirm the fieldMetadataId and operand passed to the upsert are valid for the object/field type.
  3. Re-sync metadata and re-run rls:configure (idempotent) so the field ids are current.
  4. Reproduce the upsertRowLevelPermissionPredicates mutation in the GraphQL playground to read any server-side rejection.

Example fix

// before
const predicate = data.upsertRowLevelPermissionPredicates.predicates[0];
if (!predicate) {
  throw new Error(`upsertRowLevelPermissionPredicates returned no predicates for object "${name}"`);
}

// after — surface the raw response and the field id used
const predicates = data.upsertRowLevelPermissionPredicates?.predicates ?? [];
if (predicates.length === 0) {
  throw new Error(
    `upsertRowLevelPermissionPredicates returned no predicates for object "${name}" ` +
    `(fieldMetadataId=${workspaceMemberIdFieldId}, operand=IS, response=${JSON.stringify(data)})`,
  );
}
const predicate = predicates[0];
Defensive patterns

Strategy: try-catch

Validate before calling

// Validate field metadata ids are fresh before the upsert loop.
// Re-sync metadata if any target object's partnerUser field id is stale.
for (const name of SIMPLE_TARGET_OBJECTS) {
  const info = objectInfoByName.get(name);
  if (!info?.partnerUserFieldMetadataId) {
    throw new Error(`Missing partnerUser field metadata id for ${name}; re-sync metadata`);
  }
}

Type guard

const hasPredicate = (
  r: unknown,
): r is { upsertRowLevelPermissionPredicates: { predicates: [{ id: string }] } } =>
  typeof r === 'object' && r !== null &&
  Array.isArray((r as any).upsertRowLevelPermissionPredicates?.predicates) &&
  (r as any).upsertRowLevelPermissionPredicates.predicates.length > 0;

if (!hasPredicate(data)) {
  throw new Error(`upsert returned no predicates for ${name}: ${JSON.stringify(data)}`);
}

Try / catch

try {
  await configureRls();
} catch (err) {
  // An empty predicates result is usually a stale field metadata id or a server-side guard.
  // Re-sync metadata and re-run (idempotent); if it persists, reproduce the upsert in the playground.
  console.error('rls:configure predicate upsert failed:', err instanceof Error ? err.message : err);
  process.exit(1);
}

Prevention

When it happens

Trigger: data.upsertRowLevelPermissionPredicates.predicates is empty/undefined after upserting for an object. Causes: the fieldMetadataId passed in is wrong/stale (the predicate can't bind); the operand 'IS' is unsupported for that field type; the role id is invalid; a server-side validation removed the predicate; metadata changed between the field lookup and the upsert.

Common situations: Metadata drift between findFieldByName and the upsert; wrong objectInfoByName entry passed; server version that changed the upsert return contract; field-locked field rejecting a predicate.

Related errors


AI-assisted analysis of twentyhq/twenty@1f5dd2bbd2 (2026-08-12). Data as JSON: /api/errors/1633b2da0fe14d3c. Report an issue: GitHub.