Compare commits

...
Author SHA1 Message Date
Sonarly Claude Code 03a63cd98d NaN in float column crashes GraphQLFloat serialization
https://sonarly.com/issue/5006?type=bug

A NUMBER-type field on the custom "Anrufe" object contains IEEE 754 NaN in PostgreSQL, which passes through processRecord without sanitization and is rejected by GraphQLFloat.serialize()'s isFinite() check during FindManyAnrufe query response serialization.

Fix: Added NaN/Infinity sanitization in two places within object-records-to-graphql-connection.helper.ts:

1. **formatFieldValue**: For NUMBER, NUMERIC, and POSITION field types, convert non-finite values (NaN, Infinity, -Infinity) to null before they reach GraphQL scalar serializers. This prevents GraphQLFloat.serialize() from throwing "Float cannot represent non numeric value: NaN".

2. **extractAggregatedFieldsValues**: Sanitize aggregated field values (min, max, avg, sum, percentage) that come from raw SQL queries. PostgreSQL aggregate functions propagate NaN from source data, and these values are typed as GraphQLFloat on the connection object.

Both changes convert non-finite numbers to null, which is the safe nullable fallback already used by sanitizeNumber.utli.ts in the RecordPositionService. This is a defense-in-depth fix — the input validators (validateNumberFieldOrThrow) should prevent new NaN values, but existing NaN data in the database still needs to be handled gracefully on output.
2026-03-30 14:05:53 +00:00
@@ -124,10 +124,19 @@ export class ObjectRecordsToGraphqlConnectionHelper {
return acc;
}
const sanitizedValue =
typeof aggregatedFieldValue === 'number' &&
!Number.isFinite(aggregatedFieldValue)
? null
: aggregatedFieldValue;
if (!isDefined(sanitizedValue)) {
return acc;
}
return {
...acc,
[aggregatedFieldName]:
objectRecordsAggregatedValues[aggregatedFieldName],
[aggregatedFieldName]: sanitizedValue,
};
},
{},
@@ -319,6 +328,12 @@ export class ObjectRecordsToGraphqlConnectionHelper {
case FieldMetadataType.DATE:
case FieldMetadataType.DATE_TIME:
return value instanceof Date ? value.toISOString() : value;
case FieldMetadataType.NUMBER:
case FieldMetadataType.NUMERIC:
case FieldMetadataType.POSITION:
return typeof value === 'number' && !Number.isFinite(value)
? null
: value;
default:
return value;
}