Compare commits

...
Author SHA1 Message Date
Sonarly Claude Code 9731546a5b TypeError: can't access property "position", m.toSorted(...)[0] is undefined
https://sonarly.com/issue/29071?type=bug

TypeError crash when toggling field visibility on `/objects/companies` because `currentRecordFields` Jotai state is an empty array during a view-creation/switching race window, and the production build's SWC/esbuild pipeline strips the source code's optional chaining (`?.[0]?.position`) that would otherwise safely handle the empty array.

Fix: Replaced the `toSorted(...)?.[0]?.position ?? 0` pattern with an explicit length check in both affected files.

The original optional chaining (`?.[0]?.position ?? 0`) was intended to safely handle empty arrays, but the production SWC+esbuild pipeline was stripping it, producing `toSorted(...)[0].position` in the minified bundle — which crashes with TypeError when `currentRecordFields` is empty (its default Jotai state value is `[]`).

The fix splits the expression into two statements:
```typescript
const sortedFields = currentRecordFields.toSorted(
  sortByProperty('position', 'desc'),
);
const lastPosition =
  sortedFields.length > 0 ? sortedFields[0].position : 0;
```

This is semantically identical (returns `0` for empty arrays) but uses a simple conditional branch that cannot be stripped by any minifier — it's fundamental control flow, not syntactic sugar.

Changed in two files:
- `useChangeRecordFieldVisibility.ts` (line 36-40) — the primary crash site from the Sentry trace, used by RecordTableHeaderPlusButtonContent, ViewFieldsHiddenDropdownSection, ViewFieldsVisibleDropdownSection, and other consumers
- `RecordTableFieldsDropdownHiddenFieldsContent.tsx` (line 65-69) — identical vulnerable pattern in the side-panel dashboard widget
2026-04-20 16:44:18 +00:00
2 changed files with 8 additions and 4 deletions
@@ -33,9 +33,11 @@ export const useChangeRecordFieldVisibility = (
fieldMetadataId: string;
isVisible: boolean;
}) => {
const sortedFields = currentRecordFields.toSorted(
sortByProperty('position', 'desc'),
);
const lastPosition =
currentRecordFields.toSorted(sortByProperty('position', 'desc'))?.[0]
?.position ?? 0;
sortedFields.length > 0 ? sortedFields[0].position : 0;
const shouldShowFieldMetadataItem = isVisible === true;
const correspondingRecordField = currentRecordFields.find(
@@ -62,9 +62,11 @@ export const RecordTableFieldsDropdownHiddenFieldsContent = ({
if (isDefined(existingRecordField)) {
updateRecordField(fieldMetadataId, { isVisible: true });
} else {
const sortedFields = currentRecordFields.toSorted(
sortByProperty('position', 'desc'),
);
const lastPosition =
currentRecordFields.toSorted(sortByProperty('position', 'desc'))?.[0]
?.position ?? 0;
sortedFields.length > 0 ? sortedFields[0].position : 0;
const newRecordField: RecordField = {
id: v4(),