domains / ai-agents / promptfoo/promptfoo
Null-safe value handling
When a value may be null, undefined, or structurally different than expected (e.g. legacy/persisted data, external input, or an intentionally empty override), don't assume its shape or truthiness — check explicitly and fail safe.
When a value may be null, undefined, or structurally different than expected (e.g. legacy/persisted data, external input, or an intentionally empty override), don’t assume its shape or truthiness — check explicitly and fail safe.
- Prefer
??over||when a legitimate falsy value (empty string, 0, false) must be preserved rather than treated as “absent.” For example, an explicit empty API-key override (namedKey = '') should not fall through to an unrelated default: usenamedKey ?? fallback, notnamedKey || fallback. - Before calling array-only operations (
.map,.length, iteration) on a field that may come from legacy, malformed, or externally-supplied data, verify the actual shape first (Array.isArray(...)) and provide a safe fallback (empty array/zero) instead of crashing or silently producing wrong results. For example:if (!Array.isArray(table.body)) { return 0; // don't attempt table.body.length on malformed/legacy payloads } return table.body.length; - When iterating arrays for validation, be aware that methods like
.some()/.every()skip holes in sparse arrays; usefor...of(orArray.from) when every index — including holes treated asundefined— must be checked. - Keep type declarations/schemas in sync with actual null-handling semantics: if
nullis a supported “clear this value” signal in the implementation, the corresponding input types/schemas must acceptnulltoo (and vice versa — don’t silently widen internal types to acceptnulljust to satisfy a test; validate through the proper public API boundary instead). - Avoid over-guarding operations that are already null/undefined-safe (e.g. spreading
undefinedinto an object yields{}, which is often fine); only add guards where the downstream consumer actually requires one.
Applying these checks consistently prevents silent data corruption, unexpected fallback to wrong defaults, and runtime crashes (e.g. 500s) when processing data whose null/empty/shape state deviates from the happy path.</description>