nektos/act · error

failed to handle service %s credentials: %w

Error message

failed to handle service %s credentials: %w

What it means

In the same startJobContainer flow, for each entry under the job's 'services:' map act resolves that service's registry credentials via handleServiceCredentials(spec.Credentials). Any error is wrapped with the service ID and %w, so the cause (missing secret, bad expression, invalid credentials config) chains through.

Source

Thrown at pkg/runner/run_context.go:306

		// specify the network to which the container will connect when `docker create` stage. (like execute command line: docker create --network <networkName> <image>)
		// if using service containers, will create a new network for the containers.
		// and it will be removed after at last.
		networkName, createAndDeleteNetwork := rc.networkName()

		// add service containers
		for serviceID, spec := range rc.Run.Job().Services {
			// interpolate env
			interpolatedEnvs := make(map[string]string, len(spec.Env))
			for k, v := range spec.Env {
				interpolatedEnvs[k] = rc.ExprEval.Interpolate(ctx, v)
			}
			envs := make([]string, 0, len(interpolatedEnvs))
			for k, v := range interpolatedEnvs {
				envs = append(envs, fmt.Sprintf("%s=%s", k, v))
			}
			username, password, err = rc.handleServiceCredentials(ctx, spec.Credentials)
			if err != nil {
				return fmt.Errorf("failed to handle service %s credentials: %w", serviceID, err)
			}

			interpolatedVolumes := make([]string, 0, len(spec.Volumes))
			for _, volume := range spec.Volumes {
				interpolatedVolumes = append(interpolatedVolumes, rc.ExprEval.Interpolate(ctx, volume))
			}
			serviceBinds, serviceMounts := rc.GetServiceBindsAndMounts(interpolatedVolumes)

			interpolatedPorts := make([]string, 0, len(spec.Ports))
			for _, port := range spec.Ports {
				interpolatedPorts = append(interpolatedPorts, rc.ExprEval.Interpolate(ctx, port))
			}
			exposedPorts, portBindings, err := nat.ParsePortSpecs(interpolatedPorts)
			if err != nil {
				return fmt.Errorf("failed to parse service %s ports: %w", serviceID, err)
			}

			imageName := rc.ExprEval.Interpolate(ctx, spec.Image)

View on GitHub (pinned to 4f41128141)

Solutions

  1. Identify the service from the error message and supply its secrets: act -s SERVICE_USERNAME=... -s SERVICE_PASSWORD=... matching the expressions in the workflow.
  2. docker login to the registry on the host so pulls succeed without per-service credentials, then remove the credentials block if appropriate.
  3. Verify the service's credentials expressions interpolate (act --verbose shows the underlying cause via %w).
  4. Rotate/verify the token if the registry returns 401.

Example fix

# before (workflow)
services:
  redis:
    image: registry.internal/redis:7
    credentials:
      username: ${{ secrets.REG_USER }}
      password: ${{ secrets.REG_PASS }}
# run without secrets

# after
act -s REG_USER=me -s REG_PASS=token -j test
Defensive patterns

Strategy: validation

Validate before calling

# list every secret referenced by service credentials and verify presence
python3 - <<'EOF'
import re,glob,yaml
refs=set()
for f in glob.glob('.github/workflows/*.y*ml'):
    for job in (yaml.safe_load(open(f)).get('jobs') or {}).values():
        for svc in (job.get('services') or {}).values():
            c=svc.get('credentials') or {}
            for v in c.values(): refs |= set(re.findall(r'secrets\.([A-Za-z_][\w]*)', str(v)))
print('required secrets:', sorted(refs))
EOF
# then pass each: act -s NAME=value

Prevention

When it happens

Trigger: A services.<id> block with 'credentials: username/password' referencing secrets not provided to act, or a credentials mapping that fails interpolation; the error names which service (serviceID) failed.

Common situations: Service containers from private registries (postgres from Artifactory, ghcr.io images) without -s secret flags; empty username/password after expression evaluation; expired registry token.

Related errors


AI-assisted analysis of nektos/act@4f41128141 (2026-08-15). Data as JSON: /api/errors/efcccfaef2d69643. Report an issue: GitHub.