PR #55423, authored by steipete and merged on March 26, fixes a bug that could brick any OpenClaw instance using GitHub Copilot as a model provider. The root cause is a timestamp parsing threshold that was off by one order of magnitude. The consequence was total CPU exhaustion. The fix was two conceptual changes and a clamp function.
The 10-Digit Assumption
OpenClaw's auth refresh system needs to schedule a token renewal before the token expires. Copilot returns an expires_at field that could be either a seconds-epoch or a milliseconds-epoch timestamp. To distinguish them, the code used a threshold of 1e10 (10 billion): anything above it was treated as milliseconds, anything below as seconds.
The problem: seconds-epoch timestamps crossed the 10-digit boundary decades ago. A far-future expiry like 12_345_678_901 — 11 digits, still seconds, roughly the year 2361 — would be misclassified as milliseconds and passed through without conversion. The result: the system tries to schedule a setTimeout with a delay of ~10 trillion milliseconds.
Node.js Has a Ceiling. It's Shorter Than You Think.
Node.js stores setTimeout delays as 32-bit signed integers. The maximum value is 2,147,483,647 milliseconds — about 24.8 days. Any value larger silently overflows. Node doesn't throw. It doesn't warn. It wraps the value, and the setTimeout fires almost immediately.
In this case, “almost immediately” means 1 millisecond. The refresh callback fires, computes the same enormous delay, overflows again, fires again. A hot loop. 100% CPU. The process is alive but doing nothing useful — just endlessly scheduling its own refresh.
Impact
Any OpenClaw instance using Copilot tokens with far-future or 11-digit expiry values would enter a 100% CPU hot loop on auth refresh. The instance remains running but becomes unresponsive to actual requests. A restart temporarily fixes it — until the next token refresh.
The Two-Layer Fix
steipete's patch is a belt-and-suspenders approach. Layer one: raise the seconds/milliseconds threshold from 1e10 to 1e11, so 11-digit seconds epochs are correctly classified. Layer two: a new clampRuntimeAuthRefreshDelayMs utility that caps any setTimeout delay at INT32_MAX (~24.8 days). Even if future timestamps exceed the new threshold, the clamp prevents overflow.
The second layer matters. Threshold-based format detection is inherently fragile — it works until the next timestamp format surprise. The clamp function is format-agnostic. It doesn't care whether the delay is wrong. It just ensures the system doesn't destroy itself trying to schedule it.
The Part They Didn't Fix
The PR modified both number-typed and string-typed expires_at branches. Only the number branch got a regression test. The string branch — which applies when the token field arrives as a JSON string — was changed but has no dedicated test coverage. It's the same arithmetic, so it's probably fine. But “probably fine” is how this bug was born in the first place.
There's also a changelog typo: the entry references superseded PR #55360 instead of #55423. Minor, but it means anyone tracking the fix by changelog will find the wrong PR.
The Lesson Nobody Learns
This is a class of bug that shows up everywhere timestamps cross system boundaries: the format is ambiguous, the heuristic is a magic number, and the failure mode is silent. Node.js doesn't throw on setTimeout overflow. It doesn't log. It just fires the callback immediately and lets you burn your own CPU.
The broader question for OpenClaw: how many other setTimeout calls in the codebase use unclamped delays derived from external timestamps? steipete fixed two call sites. The project has 55,000+ pull requests worth of code. There are almost certainly more.
Already patched on DeployClaw. If you were running Copilot through your OpenClaw agent, the hot loop fix shipped with the March 26 update. No action needed on your end.