Compare commits

...
Author SHA1 Message Date
Sonarly Claude Code d914039d45 fix: gracefully skip unknown fields in SSE optimistic record updates
https://sonarly.com/issue/18992?type=bug

When an SSE event delivers a record update containing custom fields that are not yet present in the frontend's cached object metadata, `computeOptimisticRecordFromInput` throws a fatal error that breaks SSE event processing for the session.

Fix: Replaced `throw new Error(...)` with `console.warn(...)` in `computeOptimisticRecordFromInput` when unknown fields are detected in the record input.

**Why this is safe:** The function's main for-loop (line 80) iterates only over `objectMetadataItem.fields`, not over `recordInput` keys. Unknown fields in `recordInput` are naturally skipped by the loop and never processed. The throw was a defensive assertion added in commit `29745c6756` for mutation-triggered optimistic updates where the frontend controls the input. When SSE real-time events were added, this function started receiving server-controlled input that may include custom fields not yet in the frontend's stale metadata cache.

**What this fixes:** When an SSE event delivers a record containing custom fields (e.g., `mail`, `pitched`, `media`, `number`, `businessCategory` on the `company` object) and the frontend's metadata cache hasn't refreshed yet, the function now logs a warning and continues processing known fields instead of crashing the entire SSE event stream handler.

Updated the test from asserting a throw to asserting a `console.warn` call and verifying that known fields are still correctly processed while unknown fields are skipped.
2026-03-27 12:59:17 +00:00
2 changed files with 29 additions and 19 deletions
@@ -252,26 +252,36 @@ describe('computeOptimisticRecordFromInput', () => {
});
});
it('should throw an error if recordInput contains fields unrelated to the current objectMetadata', () => {
it('should warn and skip unknown fields if recordInput contains fields unrelated to the current objectMetadata', () => {
const cache = new InMemoryCache();
const personObjectMetadataItem = getMockObjectMetadataItemOrThrow('person');
const consoleWarnSpy = jest
.spyOn(console, 'warn')
.mockImplementation(() => {});
expect(() =>
computeOptimisticRecordFromInput({
currentWorkspaceMember,
objectMetadataItems: getTestEnrichedObjectMetadataItemsMock(),
objectMetadataItem: personObjectMetadataItem,
recordInput: {
unknwon: 'unknown',
foo: 'foo',
bar: 'bar',
city: 'Paris',
},
cache,
objectPermissionsByObjectMetadataId: {},
}),
).toThrowErrorMatchingInlineSnapshot(
`"Should never occur, encountered unknown fields unknwon, foo, bar in objectMetadataItem person"`,
const result = computeOptimisticRecordFromInput({
currentWorkspaceMember,
objectMetadataItems: getTestEnrichedObjectMetadataItemsMock(),
objectMetadataItem: personObjectMetadataItem,
recordInput: {
unknwon: 'unknown',
foo: 'foo',
bar: 'bar',
city: 'Paris',
},
cache,
objectPermissionsByObjectMetadataId: {},
});
expect(consoleWarnSpy).toHaveBeenCalledWith(
expect.stringContaining(
'encountered unknown fields unknwon, foo, bar in objectMetadataItem person',
),
);
expect(result).toEqual({
city: 'Paris',
});
consoleWarnSpy.mockRestore();
});
});
@@ -71,8 +71,8 @@ export const computeOptimisticRecordFromInput = ({
},
);
if (unknownRecordInputFields.length > 0) {
throw new Error(
`Should never occur, encountered unknown fields ${unknownRecordInputFields.join(', ')} in objectMetadataItem ${objectMetadataItem.nameSingular}`,
console.warn(
`computeOptimisticRecordFromInput: encountered unknown fields ${unknownRecordInputFields.join(', ')} in objectMetadataItem ${objectMetadataItem.nameSingular}. Skipping unknown fields.`,
);
}