Compare commits

...
Author SHA1 Message Date
Sonarly Claude Code 1c1919e6f5 fix: skip relation fields whose target object is inactive in GQL field generation
https://sonarly.com/issue/17028?type=bug

When a workspace has a custom object (e.g. "Placement") that was deactivated, relation fields on active objects (e.g. Company.placements) still reference the inactive target. The GQL field generation throws because inactive objects are filtered from `objectMetadataItems` but their relation fields are not.

Fix: ## What changed

Two files modified to gracefully handle relation fields whose target objects are inactive/deactivated:

1. **`generateDepthRecordGqlFieldsFromFields.ts`** (line 57): Changed `throw new Error(...)` to `return recordGqlFields` — when a RELATION field's target object is not found in the active `objectMetadataItems` list, the field is simply skipped in the generated GQL fields. This is safe because the GraphQL schema won't include the inactive object's type, so requesting it would fail anyway.

2. **`useRelatedRecordCommands.ts`** (line 60): Changed `throw new Error(...)` to `continue` — when building the command menu's "Create related record" commands, relation fields pointing to inactive target objects are skipped. Users shouldn't see commands to create records for deactivated objects.

## Why

The metadata store refactor (#18647, March 14) introduced `MinimalMetadataService` which filters objects by `isActive === true`. However, field metadata is loaded separately and includes ALL fields, including relation fields pointing to inactive objects. When `generateDepthRecordGqlFieldsFromFields` iterates over Company's fields and finds "placements" (a custom RELATION field pointing to a deactivated "Placement" object), it throws because the target object is not in the filtered list.

The fix addresses the inconsistency at the consumer level — these are the two sites where the mismatch between filtered objects and unfiltered fields causes crashes. The `buildMorphRelationUpdateInput.ts` throw was intentionally left as-is since that's a write path where the error is appropriate.
2026-03-20 18:12:48 +00:00
2 changed files with 4 additions and 6 deletions
@@ -57,10 +57,9 @@ export const useRelatedRecordCommands = ({
(item) => item.nameSingular === targetObjectName,
);
// Target object may be inactive/deactivated — skip this relation
if (!isDefined(targetObjectMetadataItem)) {
throw new Error(
`Target object metadata item is undefined for field: ${field.id}`,
);
continue;
}
const targetObjectNameSingular = targetObjectMetadataItem.nameSingular;
@@ -54,10 +54,9 @@ export const generateDepthRecordGqlFieldsFromFields = ({
fieldMetadata.relation?.targetObjectMetadata.id,
);
// Target object may be inactive/deactivated — skip the relation field
if (!targetObjectMetadataItem) {
throw new Error(
`Target object metadata item not found for ${fieldMetadata.name}`,
);
return recordGqlFields;
}
const isActivityTargetField =