{"record":{"id":"efcccfaef2d69643","repo":"nektos/act","slug":"failed-to-handle-service-s-credentials-w","errorCode":null,"errorMessage":"failed to handle service %s credentials: %w","messagePattern":"failed to handle service (.+?) credentials: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/runner/run_context.go","lineNumber":306,"sourceCode":"\t\t// specify the network to which the container will connect when `docker create` stage. (like execute command line: docker create --network <networkName> <image>)\n\t\t// if using service containers, will create a new network for the containers.\n\t\t// and it will be removed after at last.\n\t\tnetworkName, createAndDeleteNetwork := rc.networkName()\n\n\t\t// add service containers\n\t\tfor serviceID, spec := range rc.Run.Job().Services {\n\t\t\t// interpolate env\n\t\t\tinterpolatedEnvs := make(map[string]string, len(spec.Env))\n\t\t\tfor k, v := range spec.Env {\n\t\t\t\tinterpolatedEnvs[k] = rc.ExprEval.Interpolate(ctx, v)\n\t\t\t}\n\t\t\tenvs := make([]string, 0, len(interpolatedEnvs))\n\t\t\tfor k, v := range interpolatedEnvs {\n\t\t\t\tenvs = append(envs, fmt.Sprintf(\"%s=%s\", k, v))\n\t\t\t}\n\t\t\tusername, password, err = rc.handleServiceCredentials(ctx, spec.Credentials)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to handle service %s credentials: %w\", serviceID, err)\n\t\t\t}\n\n\t\t\tinterpolatedVolumes := make([]string, 0, len(spec.Volumes))\n\t\t\tfor _, volume := range spec.Volumes {\n\t\t\t\tinterpolatedVolumes = append(interpolatedVolumes, rc.ExprEval.Interpolate(ctx, volume))\n\t\t\t}\n\t\t\tserviceBinds, serviceMounts := rc.GetServiceBindsAndMounts(interpolatedVolumes)\n\n\t\t\tinterpolatedPorts := make([]string, 0, len(spec.Ports))\n\t\t\tfor _, port := range spec.Ports {\n\t\t\t\tinterpolatedPorts = append(interpolatedPorts, rc.ExprEval.Interpolate(ctx, port))\n\t\t\t}\n\t\t\texposedPorts, portBindings, err := nat.ParsePortSpecs(interpolatedPorts)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to parse service %s ports: %w\", serviceID, err)\n\t\t\t}\n\n\t\t\timageName := rc.ExprEval.Interpolate(ctx, spec.Image)","sourceCodeStart":288,"sourceCodeEnd":324,"githubUrl":"https://github.com/nektos/act/blob/4f411281417e88660bea1c1a1749aa71ae0bd60f/pkg/runner/run_context.go#L288-L324","documentation":"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.","triggerScenarios":"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.","commonSituations":"Service containers from private registries (postgres from Artifactory, ghcr.io images) without -s secret flags; empty username/password after expression evaluation; expired registry token.","solutions":["Identify the service from the error message and supply its secrets: act -s SERVICE_USERNAME=... -s SERVICE_PASSWORD=... matching the expressions in the workflow.","docker login to the registry on the host so pulls succeed without per-service credentials, then remove the credentials block if appropriate.","Verify the service's credentials expressions interpolate (act --verbose shows the underlying cause via %w).","Rotate/verify the token if the registry returns 401."],"exampleFix":"# before (workflow)\nservices:\n  redis:\n    image: registry.internal/redis:7\n    credentials:\n      username: ${{ secrets.REG_USER }}\n      password: ${{ secrets.REG_PASS }}\n# run without secrets\n\n# after\nact -s REG_USER=me -s REG_PASS=token -j test","handlingStrategy":"validation","validationCode":"# list every secret referenced by service credentials and verify presence\npython3 - <<'EOF'\nimport re,glob,yaml\nrefs=set()\nfor f in glob.glob('.github/workflows/*.y*ml'):\n    for job in (yaml.safe_load(open(f)).get('jobs') or {}).values():\n        for svc in (job.get('services') or {}).values():\n            c=svc.get('credentials') or {}\n            for v in c.values(): refs |= set(re.findall(r'secrets\\.([A-Za-z_][\\w]*)', str(v)))\nprint('required secrets:', sorted(refs))\nEOF\n# then pass each: act -s NAME=value","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Map every secrets.* reference in services.<id>.credentials to an act -s flag.","Pre-authenticate the host with docker login for private registries.","The error names serviceID — fix that service's credentials first."],"tags":["services","docker","credentials","act"],"backgroundTag":null,"analyzedSha":"4f411281417e88660bea1c1a1749aa71ae0bd60f","analyzedAt":"2026-08-15T09:19:46.307Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}