Skip to main content

Troubleshooting

Most runner issues fall into one of five buckets. Start with rbtk-runner doctor, then walk the list below.

Runner never picks up a job

A runner that heartbeats ONLINE but never receives jobs is almost always a capability mismatch.

Diagnose

Common mismatches

Reload runner.yaml or restart the service after changes.

MCAP upload fails

The runner uploads MCAP files via S3 presigned URLs that the platform mints just-in-time.

Symptom

Causes and fixes

Heartbeat lapse

The platform marks a runner OFFLINE after 60 s without a heartbeat.

Diagnose

Common causes

Version skew with the platform

rbtk-runner v2.x is wire-compatible with the latest platform. If the platform advances a wire-contract minor version, the runner emits a deprecation warning, and after 90 days a hard error.

Diagnose

Fix

Upgrade via the install path you used originally:
Then drain and replace — see Run as a service.

Registration token issues

Registration tokens are single-use and live for 1 hour. Mint a new one:
If you need to register many runners (e.g., autoscaling), pre-mint a batch with --ttl 24h and --uses 50 — these flags require Enterprise tier.

Job timeouts

A job killed at the job_timeout boundary surfaces as failed with reason runner_timeout.

Diagnose

Fix

Increase resources.job_timeout in runner.yaml:
Or override per-test with timeout: in .roboticks/test.yaml.

Docker permission denied

The runner user must be in the docker group:

Disk space exhaustion

The runner cleans up containers and the work-dir between jobs, but it does not prune Docker images. Periodically:
Or wire it into a weekly systemd timer.

Getting more signal

Crank logs to debug and re-run:
debug includes every HTTP request to the platform, the full docker run command for each job, and S3 multipart upload chunk timings.

Job stays queued indefinitely

A test job that never moves past queued almost always means the pool is at capacity. The scheduler counts every HostedRunner row in PENDING, LAUNCHING, or RUNNING against the pool’s max_concurrent_runners. If a row is stuck — usually because the underlying EC2 was terminated out-of-band, the spot request failed silently, or the runner crashed before reporting terminal status — the slot stays occupied forever and new jobs sit in the queue. The platform runs a reaper every 60 s that reconciles every active HostedRunner against EC2 reality and unblocks the pool when it finds a dead row: Operationally this means:
  • Wait one reaper tick (≤ 60 s) after the failure before assuming the pool is permanently stuck.
  • A job that the reaper marked ERROR will have its error message say so. That’s the signal to look at the runner’s CloudWatch logs (cloud) or journalctl -u rbtk-runner (self-hosted) for the root cause.
  • If the same root cause keeps recurring (your test_command references a binary that isn’t in the docker image, for example), the reaper will keep cleaning up while you keep submitting failing jobs. Fix the image, not the reaper.

Verifying the reaper is running

Backend ECS task logs include Starting hosted-runner reaper (interval: 60s, ...) at startup and Reaper tick N: reaped=X orphans_terminated=Y whenever it cleans up something. If you see Job queue worker stopped gracefully without a matching started line on a newer container, the deployment is in flux — wait for it to settle.

Still stuck?

Configuration

Capabilities, resource limits, log level.

GPU setup

NVIDIA driver and container-toolkit issues.