Every reason a schedule has no next run carries a stable code
The report of a trigger's next run is the only view of a schedule an operator has. A report that cannot distinguish "fine, nothing due" from "will never fire" is the diagnostic being absent exactly when it is needed.
The rule
- An absent next run, reported on its own, means only that nothing is currently due, the answer a perfectly healthy schedule gives between fires.
- Every other reason a schedule yields no next run must be reported with a stable code:
no_expressionwhere the expression is cleared,invalid_expressionwhere it is malformed, or well-formed but unsatisfiable. - Severity must not be flattened: an unusable timezone does not stop a trigger, since the implementation substitutes UTC, so such a schedule still reports a real next run alongside the code
invalid_timezone; an expression problem, being the more consequential of the two, takes its place. - A broken stored schedule is not a broken request: the report is answered with 200 and carries the diagnosis.
What it means
A bare absent next run is not itself a diagnosis: reported alone, it is what a perfectly working schedule says between fires, so it cannot also be the answer for a schedule that will never fire at all. Any other reason for having no next run has to arrive as a named, stable code, not as the same silence a healthy schedule produces.
The same code has to come out whether the schedule was just read back from a saved record or reached through a live report — a caller cannot be left wondering whether the wording changed because the diagnosis changed or because the read path did.
Example
A stored schedule left in advanced mode with nothing typed into the expression:
{ "mode": "advanced", "cron_expression": "", "timezone": "UTC" }"no_expression"The same code comes back whether that schedule is read from a saved record or reported straight from a freshly built configuration.