Skip to content

fix: clean NaN values from entities before database save to prevent TypeORM errors - #1166

Open
Tianpapa wants to merge 2 commits into
bpatrik:masterfrom
Tianpapa:fix/clean-nan-before-db-save
Open

fix: clean NaN values from entities before database save to prevent TypeORM errors#1166
Tianpapa wants to merge 2 commits into
bpatrik:masterfrom
Tianpapa:fix/clean-nan-before-db-save

Conversation

@Tianpapa

Copy link
Copy Markdown

Problem

When EXIF metadata contains malformed GPS coordinates or other empty numeric fields, the metadata parser can produce NaN values in the entity objects. When these entities are saved to the database via TypeORM, the write fails because SQLite does not support NaN values.

This prevents photos with problematic EXIF data from being indexed, and the indexing job gets stuck retrying failed saves.

Changes

  1. Added Utils.cleanNaN() — a recursive deep-clean function that traverses an object tree and replaces NaN (both JavaScript's number NaN and the string "NaN") with null.
  2. Applied in IndexingManager.saveChunk() — entities are cleaned before being passed to repository.save(), catching NaN from any upstream source.

Design decisions

  • The fix is applied at the database layer, the lowest common point, rather than patching individual metadata parsers. This ensures robustness against NaN from any source (EXIF, Sharp, future parsers).
  • Recursive traversal handles nested entity relations.
  • Both number NaN and string "NaN" are caught, as EXIF libraries may produce either type.

When selecting a thumbnail or preview size, findClosestinSorted picks the
numerically closest value. For grid thumbnails this works fine, but for
lightbox full-screen preview the expected behavior is ceiling: pick the
next available size that is >= the display viewport.

The issue manifests on high-DPI devices: e.g. a 3200x2136px phone with
DPR=2 has a CSS viewport of ~1600px. With sizes [320, 1200, 2136, 2160],
the algorithm picks 1200px (|1600-1200|=400) instead of 2136px
(|1600-2136|=536), because closest-match favors the smaller size.

Added Utils.findCeilinginSorted() and used it in MediaIcon.getMediaSize()
for thumbnail/preview size selection. findClosestinSorted is kept for
backward compatibility.
@Tianpapa
Tianpapa force-pushed the fix/clean-nan-before-db-save branch 2 times, most recently from 8884fb3 to 57521b2 Compare June 19, 2026 08:35
EXIF metadata parsing can produce NaN values (e.g., from malformed GPS
coordinates or empty numeric fields). When these NaN values reach the
database layer, TypeORM fails to save entities because SQLite does
not support NaN.

This fix:
1. Adds Utils.cleanNaN() - a recursive deep-clean function that
   replaces NaN (both number and string "NaN") with null
2. Calls it in IndexingManager.saveChunk() before saving entities

The cleanup is done at the lowest common point (database save) to
catch NaN from any source without modifying every metadata parser.
@Tianpapa
Tianpapa force-pushed the fix/clean-nan-before-db-save branch from 57521b2 to 19d28d8 Compare June 19, 2026 08:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant