statusline: individual rate_limits windows are omitted instead of null, so a status line cannot tell "unknown" from "0% used"
The problem
In the statusline hook payload, each window inside rate_limits is emitted through a conditional spread. When a window has no data, the key is omitted from the object rather than emitted with a null value.
A status line therefore cannot distinguish two very different states:
- the window is genuinely at 0% used, and
- the window value is not known yet on this session.
Both look identical from the script's side: .rate_limits.five_hour is undefined.
Observed payload
Captured from a real session (~/.claude/statusline_debug.json, 2026-09-04T14:25:20+02:00, CLI 2.1.260, model claude-fable-5-1):
"rate_limits": { "seven_day": { "used_percentage": 47, "resets_at": 1788606000 } }
seven_day is present, five_hour is absent from the object entirely. Not null, not 0 — absent. The session was well into a working day, so 0% would not have been correct either; the value was simply not there.
Root cause in 2.1.260
The object literal that becomes rate_limits:
ko = {
...go.five_hour && { five_hour: { used_percentage: go.five_hour.utilization*100, resets_at: go.five_hour.resets_at } },
...go.seven_day && { seven_day: { used_percentage: go.seven_day.utilization*100, resets_at: go.seven_day.resets_at } },
...Ie() === "gateway" && go.overage && { spend_limit: { used_percentage: go.overage.utilization*100, resets_at: go.overage.resets_at } }
}
and the payload then carries it only if at least one key survived:
...(ko.five_hour || ko.seven_day || ko.spend_limit) && { rate_limits: ko }
So absence is overloaded: it means "no data" at the key level, and "no data for any window" at the object level.
Why this is worth fixing
The documented schema at statusline.md shows five_hour and seven_day as present fields with numeric values. A script written against that documentation reads .rate_limits.five_hour.used_percentage and gets undefined, with no way to tell whether that is a transient gap or a real zero. The only workaround is to render a placeholder such as ? and hope.
The convention for expressing "known to be unavailable" already exists in the same codebase: the get_usage control-protocol schema declares every window as .nullable().optional(), and pairs it with an explicit rate_limits_available boolean described as "False when plan rate limits do not apply (API key, Bedrock, Vertex, or missing profile scope) — rate_limits will be null."
Suggested fix
Either of these would resolve the ambiguity:
- Emit each known-but-unavailable window as
nullinstead of omitting the key, matching theget_usageschema; or - Add the
rate_limits_availableboolean to the statusline payload as well, so a script can tell "this plan has no rate limits" from "this window is not populated yet".
Environment
- Claude Code
2.1.260 - Windows 10 Pro 19045
- Model
claude-fable-5-1 - Custom statusline script reading the hook payload from stdin
Related, but not the same
#45133 and #40094 are both closed and both describe rate_limits being missing in its entirety for certain auth or plan configurations. This report is narrower: the object is present and populated, and an individual window inside it is silently absent.
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗