Skip to content
Latchkey LogoLatchkey home

Blacksmith runner not picked up, and the other errors teams hit

Blacksmith runner not picked up is, nine times out of ten, one of two things: a runs-on value that does not match a published Blacksmith tag character for character, or the Blacksmith GitHub App missing from the repository that queued the job. Both are configuration rather than product faults, and both have a documented fix.

Free minutes by runner: ARM 2 vCPU 4,800, x64 2 vCPU 3,000, 4 vCPU 1,500, 8 vCPU 750, macOS 150
What 3,000 free Blacksmith minutes buy on each runner, derived from the conversion ratios published in its instance-types FAQ, read 20 September 2026.

This page collects the failures teams hit in their first weeks on Blacksmith, with the fix for each and the Blacksmith document that describes it. Most are configuration, several are documented behavior, and the genuine product limits are labeled as such.

Everything was read from docs.blacksmith.sh and blacksmith.sh on 20 September 2026, and where Blacksmith publishes nothing this page says so. For the product overview instead of the error list, what Blacksmith CI is and Blacksmith pricing explained cover the sizes and the rate card.

The job stays queued, or quietly runs on a GitHub-hosted runner

The label is exact. Blacksmith tags are blacksmith-{n}vcpu-{os}-{version}, with -arm for ARM Linux, and the instance-types page lists every valid one. A tag that does not exist matches no runner, and GitHub does not fail that job: it waits out the 24-hour queue timeout, then cancels it.

The usual mismatches: a vCPU count that does not exist for that platform, the wrong Ubuntu suffix, an ARM label on an x64 job, and a runs-on nobody changed. Blacksmith publishes the mapping for the three starting points: ubuntu-latest to blacksmith-2vcpu-ubuntu-2404, windows-latest to blacksmith-2vcpu-windows-2025, macos-latest to blacksmith-6vcpu-macos-latest.

Check every job, not the first one. A workflow with one job on Blacksmith and three still on ubuntu-latest looks migrated and bills like it was not.

.github/workflows/ci.yml
 jobs:
   build:
-    runs-on: blacksmith-2vcpu-ubuntu-2204-arm64   # invalid: the suffix is -arm
+    runs-on: blacksmith-2vcpu-ubuntu-2204-arm

   test:
-    runs-on: blacksmith-6vcpu-ubuntu-2404        # invalid: no 6 vCPU Linux tier
+    runs-on: blacksmith-8vcpu-ubuntu-2404

Jobs queue in one repository while another repository is served

This one looks impossible, because Blacksmith states it has no concurrency limits. The mechanism is in its own FAQ: runners register through GitHub's organization-level API, so GitHub can hand a live runner any queued job in the organization whose tags match, while Blacksmith provisions capacity only where its app is installed. One repository with the app and two without means the first one's runners are consumed by work Blacksmith never saw.

The documented fix is to install the app everywhere blacksmith-* labels appear. Audit it cheaply: search the organization for runs-on: blacksmith- and compare the matches against the app's installation page.

Two adjacent failures share a cause. Blacksmith is limited to GitHub organizations, so a personal account cannot use it. And if the organization is missing from the dashboard, the quickstart names three reasons: an unauthenticated SSO session, the app not installed, or a user who is not a member.

Docker builds are not using the layer cache

Layer caching needs both Blacksmith actions: useblacksmith/setup-docker-builder@v2 configures a buildx builder with access to previous runs, and useblacksmith/build-push-action@v2 builds on it. Use the build action alone and the runner falls back to the default builder, which uses no Blacksmith layer cache and reports no analytics.

The newer trap is the cache-key input that setup-docker-builder@v2 requires. Builds sharing a key share a cache, so an unrelated image on the same key evicts your layers and can leave the build slower than no cache at all. A Dockerfile path is the documented default.

One rule catches people whose cache is configured correctly: the runner commits the cache at the end of the job, and only if no other step failed or was canceled, so a flaky test after the build means the build you paid for is not saved.

The oldest Docker rule still applies underneath all of it: a change early in the Dockerfile invalidates every layer after it, so order stable steps first and copy changing source last.

Both actions, with the cache key scoped to one Dockerfile
- uses: useblacksmith/setup-docker-builder@v2
  with:
    cache-key: services/api/Dockerfile
- uses: useblacksmith/build-push-action@v2
  with:
    push: true
    tags: user/app:latest

A sticky disk fails inside a container job

Sticky disks mount a block device, so a container job needs the container privileged and carrying five Blacksmith environment variables: VM_ID, GITHUB_REPO_NAME, BLACKSMITH_STICKYDISK_TOKEN, BLACKSMITH_INSTALLATION_MODEL_ID and BLACKSMITH_REGION, plus sudo, which slim test images usually lack.

The symptom is specific: without those steps you get a 401, an Unauthenticated error, or permission errors on mount, a signature that does not look like a disk problem. Two limits sit behind the feature: at most 5 sticky disks per job, and a disk purged after 7 days without a mount.

The container job changes a sticky disk needs
container:
  image: mcr.microsoft.com/playwright:v1.41.1
  options: --privileged
  env:
    VM_ID: ${{ env.VM_ID }}
    BLACKSMITH_STICKYDISK_TOKEN: ${{ env.BLACKSMITH_STICKYDISK_TOKEN }}

A workflow still references useblacksmith cache forks

Those actions are archived. useblacksmith/cache and the language-specific forks are unmaintained, and Blacksmith recommends moving to the upstream actions. Nothing replaces them: on a Blacksmith runner the official and popular third-party cache actions are redirected to its colocated cache, with 25 GB free per repository per week against GitHub's 10 GB, evicted after 7 days unused.

Two documented exceptions still talk to GitHub's backend: Rust's sccache and the cache option inside docker/build-push-action, so if those are your hot paths you are on GitHub's storage rules whatever the rest of the workflow does.

Entries are scoped to their branch or tag by default, matching GitHub's own restriction, and that can be turned off in the dashboard. Latchkey makes the opposite trade: its cache is a one-line swap to latchkey-dev/cache-action@v1, carrying the same inputs, with 14-day retention and per-organization isolation (dependency caching).

The first run was slow, and so was the one after a quiet week

A cold first run is expected rather than a fault. The compute is not the slow part, since the docs put microVM boot at under 3 seconds; what is cold is the cache, because the first Docker run after the switch is uncached and later runs mount the hydrated layer cache.

The one to watch is the second cold run, weeks later. The sticky disk is evicted after 7 days idle and BuildKit drops layers unused for 8 days, so a weekly pipeline pays the uncached price most times it runs, and a scheduled warm-up build inside that window is cheaper than the rebuild.

The free minutes ran out much sooner than expected

The 3,000 free minutes a month are per organization and denominated in x64 2-vCPU minutes, so bigger runners draw them down proportionally at the conversions the instance-types FAQ publishes.

RunnerDraw per minuteWhat the 3,000 free minutes buy
Ubuntu x64, 2 vCPU13,000 minutes
Ubuntu x64, 4 vCPU21,500 minutes
Ubuntu x64, 8 vCPU4750 minutes
Ubuntu x64, 32 vCPU16187 minutes
Ubuntu ARM, 2 vCPU0.6254,800 minutes
Windows x64, 2 vCPU21,500 minutes
macOS M4, 6 vCPU20150 minutes

The image is nearly GitHub's image, except where it is not

Ubuntu x64 and ARM runners carry the same dependencies as GitHub's official runner images, which is why most migrations are uneventful. Windows is the documented exception: it is based on GitHub's Windows Server 2025 image but excludes the full Visual Studio IDE in favor of VS Build Tools 2022, plus Visual Studio extensions, EdgeDriver, WinAppDriver and the Azure Cosmos DB Emulator. A job that expects any of those fails on a runner that is otherwise a drop-in.

Two platform limits are documented rather than incidental. Docker Linux containers are unsupported on Windows runners because of nested virtualization constraints, though Windows containers matching the host work through process isolation. Nested virtualization is x64 Linux only, so KVM jobs and Android emulator tests will not run on ARM.

One surprise runs the other way: when the fleet has spare capacity, Blacksmith bumps a runner to the next tier at no extra cost, so a job that asked for 4 vCPU sometimes gets 8.

When the failure is not a Blacksmith problem at all

Some failures are not about the runner vendor at all: a registry timeout, an out-of-memory kill, a disk that filled mid-job, a browser binary that did not install. On Blacksmith, as on GitHub-hosted runners, those fail the job, bill the minutes, and bill again on the re-run.

Latchkey differs on that one axis, retrying transient failures inside the same job (self-healing), while Blacksmith sells arm64, Windows, macOS and 3,000 free minutes that Latchkey does not.

Key takeaways

  • A queued job is a label that matches no runner, and GitHub waits 24 hours before canceling it rather than failing fast.
  • Install the GitHub App on every repository using blacksmith-* labels: runner registration is organization-wide, so one missing install starves the others.
  • Docker caching needs both actions plus a cache-key, and the cache is only committed if no other step in the job failed.
  • Sticky disks inside a container need privileged mode, five environment variables and sudo, or you get a 401.
  • The 3,000 free minutes are 2-vCPU minutes: 750 on an 8 vCPU runner, 150 on macOS.

Frequently asked questions

My Blacksmith job stays queued or runs on a GitHub-hosted runner. Why?
Either the runs-on value does not match a published Blacksmith tag exactly, or the GitHub App is not installed on that repository. Check the tag character for character, then the app installation. GitHub does not fail a job whose label matches nothing; it waits out the 24-hour queue timeout first.
Why was my first Blacksmith run slow?
Caches start cold, not the machine: the docs put microVM boot at under 3 seconds, but the first Docker build after switching is uncached and later runs mount the hydrated cache. If runs are a week or more apart, the 7-day sticky disk eviction and 8-day BuildKit collection mean you keep paying the cold price.
Do I need both Blacksmith Docker actions to get layer caching?
Yes. Without useblacksmith/setup-docker-builder the runner falls back to the default builder, which uses no Blacksmith layer cache and reports no analytics. The setup action also requires a cache-key that decides which builds share a cache; the documented default is the Dockerfile path.
How fast do Blacksmith free minutes run out on a larger runner?
Proportionally to size, because they are x64 2-vCPU minutes: a 4 vCPU runner draws two a minute and an 8 vCPU runner four, which is 1,500 and 750 wall-clock minutes. ARM draws 0.625, Windows double, and a 6 vCPU macOS runner 20, or 150 minutes.

Related guides

References

Queued jobs are configuration. The failures after the job starts are the ones Latchkey repairs on the runner. Start free → 30-day trial · No credit card