# Blank and Invalid Values {#blank-and-invalid-values}


This page documents what MQUAD actually does when a value is missing, blank,
malformed, or unexpected. The rules below are frozen for the calculation
functions and verified across web, mobile, and backend.

---


## The core rule: missing input → null {#the-core-rule-missing-input--null}


For every calculation function, any **missing / null / empty / malformed
argument, wrong argument count, or unknown unit** returns `null`. Functions
never throw, never abort the enclosing expression, and never produce `0` or an
empty string *just because* an input was bad.

When a calculation returns `null`, the question's stored value is left
**unchanged** (it keeps its previous value). A later valid result overwrites
it.

---


## What happens in each situation {#what-happens-in-each-situation}


| Situation | Result |
|---|---|
| Referenced question has not been answered yet | The reference resolves to blank/null → functions that use it return `null` |
| Date is invalid or malformed (`age('not-a-date', '2026-08-14')`) | `null` |
| Calculation argument is null (`bmi(null, 175)`) | `null` — **not** `0` |
| Unit is unknown (`date-diff('fortnights', ...)`) | `null` |
| Height is zero or negative (`bmi(70, 0)`) | `null` |
| Weight is non-numeric (`bmi('abc', 175)`) | `null` |
| Wrong argument count (`age('2000-01-01')`) | `null` |
| End date before start date (`date-diff('days', ${end}, ${start})`) | a **negative** number (date-diff is signed) |
| LMP after reference date (`gestational-weeks(${future_lmp}, ${visit})`) | `0` (gestational functions clamp to 0) |
| DOB after reference date (`age(${future_dob}, ${visit})`) | `0` (age functions clamp to 0) |
| Mixed plain-time + datetime (`time-diff('hours', '09:00', '2026-08-14T10:00:00Z')`) | `null` |
| Question is hidden by skip logic | its stored answer is retained; if it was never answered, references resolve to blank |
| Non-numeric amount in date-add (`date-add('2026-08-14', 'x', 'days')`) | `null` |


### Worked examples {#worked-examples}


```text
bmi(null, 175)                    → null
date-diff('fortnights', '2026-08-01', '2026-08-14')  → null
date-diff('months', '', '2026-08-14')                → null
age('not-a-date', '2026-08-14')   → null
date-add('2026-08-14', 'x', 'days') → null
```

MQUAD does **not** show a visible error message when a function returns null —
the result is simply blank. If blank results are a problem, add a
[Validation](/user-manual/validation.md) rule to prevent bad input in the first place.

---


## Validation vs null {#validation-vs-null}


Validation (constraints) is **skipped for empty values** — an unanswered
question only fails if it is marked **Required**. This means:

- An empty `symptoms` answer does not fail `count-selected(${symptoms}) >= 2`.
- It fails only if the field is Required.

If a field must be validated *only when answered*, that is the default
behaviour. If it must be required under a condition, use:

```text
if(${has_children} = 'yes', . != '', .)
```


## Hidden questions {#hidden-questions}


When a question is hidden by [Skip Logic](/user-manual/skip-logic.md), its previously entered
answer is **retained**, not erased. References to a hidden-but-answered
question still resolve. If a question was never shown and never answered,
references to it resolve to blank.

If you need a hidden question's stale value cleared, add a calculation that
clears it (e.g. an `if()` that yields blank), or clear it manually.


## Preventing problems {#preventing-problems}


Because null results are silent, the practical guidance is:

1. **Validate inputs** — numeric range checks (`bmi`, age inputs), date order
   checks (end ≥ start), required checks.
2. **Use the signed rule** — `date-diff` returns negatives for reversed dates;
   validate with `${end_date} >= ${start_date}` instead of guessing.
3. **Reference dates explicitly** — `age(${dob}, ${interview_date})` fails to
   `null` if either date is blank; make both questions Required.
4. **Test in Preview** — open your survey in Preview mode and step through the
   cases you care about before publishing.
