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
- Inspect the full upsert response (data.upsertRowLevelPermissionPredicates) for an errors/null payload — log it before the guard.
- Confirm the fieldMetadataId and operand passed to the upsert are valid for the object/field type.
- Re-sync metadata and re-run rls:configure (idempotent) so the field ids are current.
- 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
- Re-sync metadata before running rls:configure so field metadata ids are current.
- Inspect the full upsert response when predicates come back empty — log it before the guard.
- Confirm the operand ('IS') is supported for the field type.
- Reproduce upsertRowLevelPermissionPredicates in the GraphQL playground to read any server rejection.
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
- GraphQL errors: ${json.errors.map((e) => e.message).join(';
- Field "${fieldName}" not found on object "${objectName}" aft
- Object "${name}" not found in workspace metadata. Has the ap
- workspaceMember object not found in workspace metadata.
- Missing env var: ${name}
AI-assisted analysis of twentyhq/twenty@1f5dd2bbd2 (2026-08-12).
Data as JSON: /api/errors/1633b2da0fe14d3c.
Report an issue: GitHub.