A cryptic error: "Failed to execute 'bound' on 'IDBKeyRange': The parameter is not a valid key." This is the story of how we found, understood, and permanently fixed a bug that could have broken every View in the system.
The Bug
Views were crashing randomly. Not consistently—some worked, some didn't. The error message was IndexedDB's way of saying "you gave me garbage".
We traced it to Dexie's where() and between() methods. These translate to IDBKeyRange.bound() internally. When you pass invalid values—undefined, NaN, Infinity, or the wrong types—IndexedDB explodes.
Root Cause Analysis
The bug had multiple potential entry points:
// These are all invalid IndexedDB keys: undefined // Not a key at all NaN // Invalid number Infinity // Invalid number true / false // Booleans aren't keys { object: 1 } // Objects aren't keys [undefined, 123] // Array with invalid element
The core issue: we trusted filter values. Users could create Views with any filter values, and those values went straight to IndexedDB without validation.
The Fix: Defensive Validation
We built a multi-layer defense system:
Layer 1: View Validator
A new module (view-validator.ts) that validates every filter value BEFORE it touches IndexedDB. Invalid values are caught early with clear error messages.
Layer 2: Value Normalization
Filter values are normalized by field type. Dates become timestamps. Amounts stay integers. IDs stay strings. No implicit type coercion at query time.
Layer 3: Repository Guards
Every repository method that uses indexed queries now validates its parameters. No undefined workspaceIds, no NaN timestamps.
Layer 4: Error Context
When validation fails, we capture the exact filter that failed, the value it received, and why it's invalid. No more cryptic IndexedDB errors.
The Validation Rules
We defined explicit rules for each filter type:
// Field Type → Expected Value date → number (timestamp, not NaN, finite) amount → number (integer, not NaN, finite) accountId → string (non-empty) categoryId → string | null type → string ('income'|'expense'|'transfer') reconciledAt → number | null (timestamp or null) payee → string description → string // Operator-specific validation between → [min, max] both defined, min <= max in/nin → non-empty array of valid primitives isNull → no value validation needed
User-Facing Errors
Invalid filters now produce clear messages:
"Filter 1 (date between): start value (min) cannot be undefined or null"
"Filter 2 (accountId in): 'in' operator requires a non-empty array"
"Configuration error: Workspace ID is required but was undefined"
No more guessing what went wrong. Users can fix their filters immediately.
Why This Matters for AI and Sharing
This hardening isn't just about fixing bugs—it's about trust:
- AI-generated Views — When AI creates Views, they must be validated. An AI can't crash the system with bad filters.
- Imported Views — Views shared via links or templates must be safe to execute. Validation ensures they can't corrupt local data.
- Deterministic Results — Same View definition = same results. Invalid values can't cause non-deterministic failures.
Execution Logging
For debugging, the QueryEngine now logs execution context (local-only, no telemetry):
// Success [QueryEngine] Execution completed: { viewId: "abc123", viewName: "Spending by Category", duration: 45, transactionsLoaded: 150, transactionsFiltered: 87 } // Failure [QueryEngine] View execution failed: { viewId: "xyz789", filterErrors: [{ filterIndex: 0, field: "date", operator: "between", message: "start value must be a valid number" }] }
Test Coverage
We added regression tests covering:
- All built-in Views execute without error
- Undefined/null workspaceId is rejected
- NaN/Infinity filter values are rejected
- Between operator validates both endpoints
- In/nin operators require non-empty arrays
- Invalid filters fail gracefully with clear messages
Key Takeaway
Never trust user input at the database layer. Dexie doesn't validate for you. IndexedDB doesn't validate for you. Validation must happen before queries are built.
This fix ensures that Views are reliable, deterministic, and safe—the foundation we need before building the Rules Engine.
— The Accelerate Finance Team