Skip to content

AutoscalingRunnerSet remains permanently Outdated after runner template replacement #4596

Description

@omersadika

Checks

Controller Version

0.14.2

Deployment Method

Helm

Checks

  • This isn't a question or user support case (For Q&A and community support, go to Discussions).
  • I've read the Changelog before submitting this issue and I'm sure it's not due to any recently-introduced backward-incompatible changes

To Reproduce

1. Install `gha-runner-scale-set-controller` and `gha-runner-scale-set` version `0.14.2` using Helm.
2. Configure the scale set with `minRunners: 0` and controller update strategy `immediate`.
3. Allow the scale set to create and run ephemeral runners.
4. Change the runner pod template in a way that changes its specification hash. For example, add labels and required pod anti-affinity.
5. Allow ARC to replace the outdated ephemeral runner set.
6. Observe ARC deleting the old listener and ephemeral runner resources.
7. Observe that the `AutoscalingRunnerSet` remains in `status.phase: Outdated` after cleanup.
8. Confirm that there is no `AutoscalingListener`, `EphemeralRunnerSet`, `EphemeralRunner`, or runner pod.
9. Observe that queued GitHub Actions jobs do not create replacement runners.

Describe the bug

After changing the runner pod template, ARC cleaned up the previous listener and ephemeral runner set but left the AutoscalingRunnerSet permanently in the Outdated phase.

The resulting resource had no runner-scale-set-id annotation but retained stale runner counts:

metadata:
  annotations:
    actions.github.com/runner-scale-set-name: example-scale-set
status:
  phase: Outdated
  currentRunners: 5
  pendingEphemeralRunners: 0
  runningEphemeralRunners: 5

There were actually no AutoscalingListener, EphemeralRunnerSet, EphemeralRunner, or runner pods.

The controller remained healthy and did not report an authentication, RBAC, or scheduling failure. Its reconciliation stopped after logging:

AutoscalingRunnerSet AutoscalingListener does not exist.
AutoscalingRunnerSet Ephemeral runner set is outdated
AutoscalingRunnerSet Deleting the listener
AutoscalingRunnerSet Listener is deleted
AutoscalingRunnerSet deleting ephemeral runner sets
AutoscalingRunnerSet All ephemeral runner sets are deleted
AutoscalingRunnerSet deleting runner scale set

Resetting only the status phase to Pending immediately recovered the deployment:

kubectl -n arc-runners patch \
  autoscalingrunnerset example-scale-set \
  --subresource=status \
  --type=merge \
  -p '{
    "status": {
      "phase": "Pending",
      "currentRunners": 0,
      "pendingEphemeralRunners": 0,
      "runningEphemeralRunners": 0,
      "failedEphemeralRunners": 0
    }
  }'

ARC then created a new GitHub runner scale set, listener, ephemeral runner set, and runners for the queued jobs. This confirmed that GitHub App authentication, Kubernetes RBAC, and runner scheduling were working.

The relevant reconciliation path appears to return successfully after cleanup without resetting the phase or explicitly requeueing:

https://github.com/actions/actions-runner-controller/blob/gha-runner-scale-set-0.14.2/controllers/actions.github.com/autoscalingrunnerset_controller.go#L246-L267

When the runner-scale-set-id annotation has already been removed, cleanup also returns successfully without changing the resource:

https://github.com/actions/actions-runner-controller/blob/gha-runner-scale-set-0.14.2/controllers/actions.github.com/autoscalingrunnerset_controller.go#L658-L706

This appears to leave the resource permanently in the Outdated phase without generating another event that would trigger creation of the replacement scale set.

Describe the expected behavior

After cleaning up an outdated runner set, ARC should transition the AutoscalingRunnerSet to a state that allows reconciliation to continue, or explicitly requeue the resource.

ARC should then create:

  1. A replacement GitHub runner scale set
  2. A new EphemeralRunnerSet
  3. A new AutoscalingListener
  4. New runners for queued jobs

The AutoscalingRunnerSet should not remain permanently in the Outdated phase after the previous listener, ephemeral runner resources, and runner-scale-set-id annotation have been removed.

The status runner counts should also be reset or updated so they do not report running runners when no corresponding EphemeralRunner resources or runner pods exist.

Additional Context

# gha-runner-scale-set-controller uses the chart defaults.
# The effective controller update strategy is "immediate".

# Sanitized gha-runner-scale-set values.yaml
githubConfigUrl: https://github.com/example-org
githubConfigSecret: example-github-config
runnerScaleSetName: example-scale-set

minRunners: 0
maxRunners: 8

controllerServiceAccount:
  name: arc-controller
  namespace: arc-system

template:
  metadata:
    labels:
      example.com/runner-scale-set: example-scale-set
  spec:
    affinity:
      podAntiAffinity:
        requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
              matchLabels:
                example.com/runner-scale-set: example-scale-set
            topologyKey: kubernetes.io/hostname

    containers:
      - name: runner
        image: ghcr.io/actions/actions-runner:latest
        command:
          - /home/runner/run.sh
        volumeMounts:
          - name: work
            mountPath: /home/runner/_work

    volumes:
      - name: work
        emptyDir: {}

Controller Logs

2026-08-07T12:45:15Z INFO AutoscalingRunnerSet AutoscalingListener does not exist. {"version":"0.14.2","autoscalingrunnerset":{"name":"example-scale-set","namespace":"arc-runners"}}
2026-08-07T12:45:15Z INFO AutoscalingRunnerSet Ephemeral runner set is outdated {"version":"0.14.2","autoscalingrunnerset":{"name":"example-scale-set","namespace":"arc-runners"}}
2026-08-07T12:45:15Z INFO AutoscalingRunnerSet Deleting the listener {"version":"0.14.2","autoscalingrunnerset":{"name":"example-scale-set","namespace":"arc-runners"}}
2026-08-07T12:45:15Z INFO AutoscalingRunnerSet Listener is deleted {"version":"0.14.2","autoscalingrunnerset":{"name":"example-scale-set","namespace":"arc-runners"}}
2026-08-07T12:45:15Z INFO AutoscalingRunnerSet deleting ephemeral runner sets {"version":"0.14.2","autoscalingrunnerset":{"name":"example-scale-set","namespace":"arc-runners"}}
2026-08-07T12:45:15Z INFO AutoscalingRunnerSet All ephemeral runner sets are deleted {"version":"0.14.2","autoscalingrunnerset":{"name":"example-scale-set","namespace":"arc-runners"}}
2026-08-07T12:45:15Z INFO AutoscalingRunnerSet deleting runner scale set {"version":"0.14.2","autoscalingrunnerset":{"name":"example-scale-set","namespace":"arc-runners"}}

# No further reconciliation occurred for approximately 12 minutes.
# The following lines appeared immediately after manually resetting status.phase to Pending.

2026-08-07T12:57:49Z INFO AutoscalingRunnerSet Runner scale set id annotation does not exist. Creating a new runner scale set. {"version":"0.14.2","autoscalingrunnerset":{"name":"example-scale-set","namespace":"arc-runners"}}
2026-08-07T12:57:50Z INFO AutoscalingRunnerSet Created/Reused a runner scale set {"version":"0.14.2","autoscalingrunnerset":{"name":"example-scale-set","namespace":"arc-runners"},"id":3,"runnerGroupName":"Default"}
2026-08-07T12:57:50Z INFO AutoscalingRunnerSet Updated with runner scale set ID, name and runner group name as an annotation {"version":"0.14.2","autoscalingrunnerset":{"name":"example-scale-set","namespace":"arc-runners"},"id":3,"name":"example-scale-set","runnerGroupName":"Default"}
2026-08-07T12:57:50Z INFO AutoscalingRunnerSet Latest runner set does not exist. Creating a new runner set. {"version":"0.14.2","autoscalingrunnerset":{"name":"example-scale-set","namespace":"arc-runners"}}
2026-08-07T12:57:50Z INFO AutoscalingRunnerSet Creating a new EphemeralRunnerSet resource {"version":"0.14.2","autoscalingrunnerset":{"name":"example-scale-set","namespace":"arc-runners"}}
2026-08-07T12:57:50Z INFO AutoscalingRunnerSet Created a new AutoscalingListener resource {"version":"0.14.2","autoscalingrunnerset":{"name":"example-scale-set","namespace":"arc-runners"},"name":"example-scale-set-listener","namespace":"arc-system"}
2026-08-07T12:57:53Z INFO EphemeralRunnerSet Creating new ephemeral runners (scale up) {"version":"0.14.2","ephemeralrunnerset":{"name":"example-ephemeral-runner-set","namespace":"arc-runners"},"count":3}
2026-08-07T12:57:54Z INFO EphemeralRunner Created ephemeral runner pod {"version":"0.14.2","ephemeralrunner":{"name":"example-runner-1","namespace":"arc-runners"},"runnerScaleSetId":3,"configUrl":"https://github.com/example-org"}
2026-08-07T12:57:54Z INFO EphemeralRunner Created ephemeral runner pod {"version":"0.14.2","ephemeralrunner":{"name":"example-runner-2","namespace":"arc-runners"},"runnerScaleSetId":3,"configUrl":"https://github.com/example-org"}
2026-08-07T12:57:55Z INFO EphemeralRunner Created ephemeral runner pod {"version":"0.14.2","ephemeralrunner":{"name":"example-runner-3","namespace":"arc-runners"},"runnerScaleSetId":3,"configUrl":"https://github.com/example-org"}

Runner Pod Logs

# No runner pod logs were available during the failure because no runner pods existed.

$ kubectl -n arc-runners get pods
No resources found in arc-runners namespace.

# The AutoscalingRunnerSet status incorrectly reported five running runners:
#
# status:
#   phase: Outdated
#   currentRunners: 5
#   pendingEphemeralRunners: 0
#   runningEphemeralRunners: 5
#
# There were no corresponding EphemeralRunner resources or Kubernetes pods.
#
# After manually resetting status.phase to Pending, ARC immediately created
# replacement runner pods. Those runners registered successfully and began
# executing the queued jobs, so there was no runner-container error to report.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workinggha-runner-scale-setRelated to the gha-runner-scale-set modeneeds triageRequires review from the maintainers

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions