GitHub Actions self-hosted runner should handle system clock skew gracefully instead of exiting permanently
Nobody has claimed this yet.
- Dominant language
- C#
- Stars
- 6.3k
- Forks
- 1.4k
- Avg merge
- 1d 16h
- Merged PRs (30d)
- 24
Description
Summary
A self-hosted GitHub Actions runner can fail during boot if the machine's system clock has not yet synchronized.
When this happens, GitHub rejects the runner's OAuth token because the local clock is significantly behind the GitHub server time. However, the runner reports:
Failed to create a session. The runner registration has been deleted from the server, please re-configure.
Runner registrations are automatically deleted for runners that have not connected to the service recently.
This message is misleading because the runner registration has not actually been deleted.
More importantly, the runner exits and does not retry after the system clock becomes synchronized. Since the systemd service then remains inactive, the self-hosted runner stays offline until manually restarted.
Environment
- Self-hosted GitHub Actions runner
- Runner version:
2.336.0 - Linux / Raspberry Pi
- Runner installed using
svc.sh - systemd
systemd-timesyncd- Runner service enabled at boot
What happened
The runner service started correctly during boot:
Aug 24 15:10:40 systemd[1]: Started GitHub Actions Runner
The runner successfully reached GitHub:
√ Connected to GitHub
But session creation failed:
POST request to https://tokenghub.actions.githubusercontent.com/... failed.
HTTP Status: BadRequest
The underlying exception contained the actual cause:
GitHub.Services.OAuth.VssOAuthTokenRequestException:
The token expired on 08/24/2026 19:15:44.
Current server time is 08/25/2026 01:44:14.
The system clock was several hours behind because NTP synchronization had not completed yet.
The runner then converted this into:
Failed to create a session. The runner registration has been deleted from the server, please re-configure.
and exited:
Runner listener exited with error code 1
Runner listener exit with terminated error, stop the service, no retry needed.
Several hours later, after NTP synchronized the system clock, simply running:
sudo ./svc.sh start
caused the same runner registration to connect successfully:
√ Connected to GitHub
Current runner version: '2.336.0'
Listening for Jobs
No re-registration or configuration change was required.
Expected behavior
The runner should ideally detect this situation and handle it gracefully.
For example:
- If OAuth authentication fails because a token appears expired but the server time differs significantly from the local clock, report a clock-skew-specific error.
- Retry session creation for some period instead of permanently terminating the runner service.
- Avoid reporting that the runner registration has been deleted unless the server has actually confirmed that condition.
A message such as:
Authentication failed because the system clock appears to differ significantly from GitHub server time.
Check NTP/time synchronization. Retrying...
would make the actual problem much easier to diagnose.
Current workaround
I added the following systemd dependency to prevent the runner from starting before time synchronization:
[Unit]
Wants=network-online.target systemd-time-wait-sync.service
After=network-online.target systemd-time-wait-sync.service
This prevents the issue on systems using systemd-timesyncd, but it is platform-specific and shouldn't be necessary for the runner to recover from temporary clock skew.
Suggested improvement
The runner does not necessarily need to manage system time itself.
However, session/authentication failures caused by clock skew should be treated as potentially transient.
In particular, the runner could:
- distinguish clock-skew/token-time errors from deleted runner registrations;
- retry authentication with exponential backoff;
- log the local and GitHub server time when a significant discrepancy is detected;
- remain running so that it can reconnect once NTP corrects the clock.
This would make self-hosted runners much more resilient after reboots, power loss, RTC issues, or delayed NTP synchronization.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the runner listener's session-creation path and the OAuth failure described in the issue; the reported exit code 1 shows where the service stops. Reproduce the boot-time clock-skew case or add focused coverage for it. Done means clock-skew failures are distinguishable from deleted registrations and the runner remains able to reconnect after time synchronization.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- csharp, github-actions, linux
- Domain
- ci-cd, devops, infrastructure
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 50/100