twentyhq/twenty · error · Error

upsertRowLevelPermissionPredicates returned no predicate for

Error message

upsertRowLevelPermissionPredicates returned no predicate for workspaceMember

What it means

Thrown by the partner RLS script after upserting a single workspaceMember predicate (`id IS the current member`) that scopes the partner role's read to its own member record. The code indexes `predicates[0]` from the mutation result; if the array is empty the predicate was not persisted, so the role would have no scoping rule and the script aborts. Like error 20, this is a provisioning-script hard stop, not user-facing runtime.

Source

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

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

    const wmPredicate =
      wmData.upsertRowLevelPermissionPredicates.predicates[0];

    if (!wmPredicate) {
      throw new Error(
        'upsertRowLevelPermissionPredicates returned no predicate for workspaceMember',
      );
    }

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

  console.log(
    `\n[rls:configure] Done — ${results.length} predicates upserted on Partner role ` +
      `(${SIMPLE_TARGET_OBJECTS.length} simple objects + opportunity OR group + workspaceMember self-scope)`,
  );
  console.log(`\n${APPLY_WORKFLOW_WARNING}`);

  // ── 5. Verify Opportunity field permissions (set via manifest, not here — see header) ─

View on GitHub (pinned to 1f5dd2bbd2)

Solutions

  1. Log `wmData.upsertRowLevelPermissionPredicates` in full before the index access to confirm whether `predicates` is empty versus the whole response being malformed.
  2. Verify `workspaceMemberIdFieldId` and `workspaceMemberId` (object metadata id) resolve to the workspaceMember object/field in this workspace via a `fieldMetadata`/`objectMetadata` query.
  3. Confirm `partnerRole.id` is still valid and that RLS is enabled on the workspaceMember object.
  4. Re-run against a freshly reset workspace so the metadata IDs the script depends on are present.

Example fix

// before
const wmPredicate = wmData.upsertRowLevelPermissionPredicates.predicates[0];
if (!wmPredicate) {
  throw new Error('upsertRowLevelPermissionPredicates returned no predicate for workspaceMember');
}

// after — guard the whole response shape, not just index 0
const wmPredicates = wmData?.upsertRowLevelPermissionPredicates?.predicates;
if (!Array.isArray(wmPredicates) || wmPredicates.length === 0) {
  throw new Error(
    `upsertRowLevelPermissionPredicates returned no predicate for workspaceMember (roleId=${partnerRole.id}, fieldMetadataId=${workspaceMemberIdFieldId})`,
  );
}
Defensive patterns

Strategy: validation

Validate before calling

// Before the workspaceMember upsert, confirm the field + object exist.
const wmField = await fetchFieldMetadataById(metadataUrl, apiKey, workspaceMemberIdFieldId);
if (!wmField) {
  throw new Error(`workspaceMember field ${workspaceMemberIdFieldId} not found in workspace`);
}

Type guard

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

Prevention

When it happens

Trigger: Calling `upsertRowLevelPermissionPredicates` for the workspaceMember object with a `workspaceMemberIdFieldId` or `workspaceMemberId` (object metadata id) that does not exist in the target workspace, with RLS disabled on workspaceMember, or with a `partnerRole.id` that has already been deleted. An empty `predicates` array in the response triggers it.

Common situations: Running the configure script against a workspace that was reset or seeded with different universal identifiers, pointing at the wrong environment, or a stale `partnerRole` lookup earlier in the script that returned a role id the metadata layer rejects.

Related errors


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