Skip to content
DevOps AI ToolKit
Newsletter
All guides
GCP with AI By James Joyner IV · · 9 min read

GCP Error Guide: 'Service account does not exist' NOT_FOUND Unknown Service Account

Fix GCP 'Service account ... does not exist / NOT_FOUND: Unknown service account': diagnose typos, deleted SAs, stale unique IDs, and wrong-project refs with read-only gcloud.

  • #gcp
  • #troubleshooting
  • #errors
  • #iam

Exact Error Message

A deployment, IAM binding, or resource creation fails because the referenced service account cannot be resolved:

$ gcloud run deploy api --service-account=runner@app-prod.iam.gserviceaccount.com ...
ERROR: (gcloud.run.deploy) Service account
'runner@app-prod.iam.gserviceaccount.com' does not exist.

The API / Terraform form is usually:

Error 400: Service account runner@app-prod.iam.gserviceaccount.com does not exist.,
badRequest

or, when a binding references the account by its numeric unique ID:

google.api_core.exceptions.NotFound: 404 NOT_FOUND: Unknown service account
deleted:serviceAccount:runner@app-prod.iam.gserviceaccount.com?uid=103294857120394857120

This comes from the iam subsystem whenever a caller references a service-account identity that IAM cannot find in the named project.

What the Error Means

Every service account has two identifiers: its email (name@project.iam.gserviceaccount.com) and an immutable unique ID (a numeric uniqueId). IAM resolves references by email but stores bindings internally against the unique ID. does not exist / NOT_FOUND: Unknown service account means IAM looked up the identity you supplied and found no live service account matching it in that project.

Note: this is not the same as iam.serviceAccounts.actAs permission denied. That error means the SA exists but the caller is not allowed to impersonate it. Here, the account genuinely cannot be resolved at all — it was never there, it was deleted, the email is mistyped, or a binding points at a stale unique ID from an account that was deleted and recreated. (For the impersonation-permission case, see the separate actAs guide under /categories/gcp/.)

Common Causes

  • Typo in the email — wrong project ID, a transposed character, or iam.gserviceaccount.com misspelled (e.g. gserviceacount).
  • The service account was deleted. Anything still referencing it (Cloud Run, a workflow, an IAM binding, a Compute instance template) now points at nothing.
  • Deleted-then-recreated SA with a stale unique ID. You recreated the same email, but a stored binding still pins the old uniqueId, so IAM renders it as deleted:serviceAccount:...?uid=<old-id> and reports unknown.
  • Wrong project context. The SA lives in app-shared but you referenced it (or ran the command) against app-prod.
  • Referencing the default compute/App Engine SA that was disabled or deleted by an org policy or cleanup.
  • The SA is disabled — some operations report it as effectively not usable.
  • Eventual consistency — you created the SA seconds ago and the reference raced ahead of propagation.

How to Reproduce the Error

  1. Create a service account: gcloud iam service-accounts create runner --project=app-prod.
  2. Grant it a role and reference it in a Cloud Run service.
  3. Delete it: gcloud iam service-accounts delete runner@app-prod.iam.gserviceaccount.com.
  4. Recreate the same email: gcloud iam service-accounts create runner --project=app-prod. It now has a brand-new uniqueId.
  5. Re-run an operation whose stored IAM binding still pins the original numeric ID. IAM returns NOT_FOUND: Unknown service account ...?uid=<old-id> because the old unique ID no longer resolves, even though the email exists again.

Diagnostic Commands

All read-only. Verify existence, the unique ID, the project, and where the SA is referenced.

# 1. Confirm which project the command will target
gcloud config get-value project

# 2. Does the service account exist? Show its email, uniqueId, and disabled state
gcloud iam service-accounts describe runner@app-prod.iam.gserviceaccount.com \
  --format="yaml(email, uniqueId, disabled, name)"

# 3. List ALL service accounts in the project to catch typos / wrong project
gcloud iam service-accounts list --project=app-prod \
  --format="table(email, uniqueId, disabled)"

# 4. Inspect the project IAM policy for stale 'deleted:' bindings with a ?uid
gcloud projects get-iam-policy app-prod --format=json | \
  grep -i "deleted:serviceAccount"

# 5. Same check, but on a specific resource (example: a Cloud Run service)
gcloud run services get-iam-policy api --region=us-central1 --format=json | \
  grep -i serviceAccount

# 6. Confirm what identity a resource currently references (Cloud Run example)
gcloud run services describe api --region=us-central1 \
  --format="value(spec.template.spec.serviceAccountName)"

# 7. Check the caller's own permissions on the SA (does not modify anything)
gcloud iam service-accounts get-iam-policy \
  runner@app-prod.iam.gserviceaccount.com --format=json

If step 2 returns the account but its uniqueId differs from the ?uid= value in step 4, you have a stale-unique-ID mismatch from a delete/recreate.

Step-by-Step Resolution

  1. Fix typos first. Compare the failing email character-for-character against gcloud iam service-accounts list. Most occurrences are a wrong project ID or a misspelled domain suffix.
  2. If the SA was deleted and you still need it, recreate it (same display name/email) or, within the ~30-day window, undelete by unique ID:
    gcloud iam service-accounts undelete <OLD_UNIQUE_ID>
    Undelete restores the original uniqueId, which repairs stale bindings without further edits.
  3. If you already recreated it with a new unique ID, purge the stale deleted: bindings and re-add the role to the live email:
    # Remove the dangling binding that pins the old uid (shown in diagnostics step 4)
    gcloud projects remove-iam-policy-binding app-prod \
      --member="deleted:serviceAccount:runner@app-prod.iam.gserviceaccount.com?uid=<OLD_UID>" \
      --role="roles/run.invoker"
    # Re-grant to the current account
    gcloud projects add-iam-policy-binding app-prod \
      --member="serviceAccount:runner@app-prod.iam.gserviceaccount.com" \
      --role="roles/run.invoker"
  4. Point the resource at a valid SA. Update the Cloud Run service / instance template / workflow to reference an account that exists in the correct project.
  5. If the SA is in another project, run the operation against that project or grant cross-project access, then reference the full email explicitly.
  6. If it is merely disabled, re-enable it: gcloud iam service-accounts enable runner@app-prod.iam.gserviceaccount.com.
  7. If you just created it, wait a short period for propagation and retry; brand-new identities are eventually consistent.

For end-to-end triage of IAM-driven deploy failures, see /dashboard/incident-response/.

Prevention and Best Practices

  • Manage SAs as code (Terraform / Config Connector) so deletions and references stay in lockstep and accidental deletes are caught in review.
  • Never delete a service account that still has bindings or attached resources. Audit references first with get-iam-policy across the projects that use it.
  • Prefer undelete over recreate when restoring a recently deleted SA, so the original unique ID (and all bindings) survive.
  • Reference SAs by their canonical full email and pin the project ID explicitly in scripts.
  • Periodically scan IAM policies for deleted:serviceAccount entries and clean them up before they break a deploy.
  • Use a small set of long-lived, well-documented SAs rather than churning ephemeral ones that leave stale references behind.
  • iam.serviceAccounts.actAs denied — the SA exists but the caller cannot impersonate it (a permission issue, not a missing identity).
  • Permission 'iam.serviceAccounts.get' denied — you cannot even read the SA; an access problem, not absence.
  • Service account key does not exist — a missing key, not a missing account.
  • The caller does not have permission (403) — generic IAM authorization failure on another resource.
  • Precondition check failed on setIamPolicy — usually a concurrent-edit etag mismatch, not a missing SA.

Frequently Asked Questions

The email looks correct, so why does it say the account does not exist? Run gcloud iam service-accounts describe against the exact project. The most common cause is a wrong project ID in the email or running the command in a different project context than where the SA lives.

I recreated the same email but still get NOT_FOUND with a ?uid= value — why? IAM bindings store the numeric unique ID, not the email. Recreating produces a new unique ID, so any binding still pinning the old uid becomes a deleted:serviceAccount ghost. Remove those stale bindings and re-grant to the live account, or undelete the original to keep its unique ID.

Can I recover a deleted service account? Often yes, within roughly 30 days. Find the original unique ID and run gcloud iam service-accounts undelete <UNIQUE_ID>. This restores the same identity and unique ID, repairing existing references automatically.

Is this the same as the actAs permission error? No. actAs denied means the account exists but you are not allowed to use it. This error means IAM cannot find the account at all. Diagnose them differently: describe proves existence; get-iam-policy reveals impersonation rights.

Why did the error appear right after I created the account? Service-account creation is eventually consistent. A reference made within a few seconds can race ahead of propagation. Retry after a short wait before assuming a deeper problem.

How do I find every resource that references a deleted SA? Scan project and resource IAM policies with get-iam-policy for deleted:serviceAccount, and check attached identities on resources (Cloud Run, instance templates, workflows, schedulers) with their respective describe commands. Cloud Asset Inventory can search references at scale.

Free download · 368-page PDF

Download the Free 500-Prompt DevOps AI Toolkit

500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.

  • 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
  • Instant PDF download — yours free, forever
  • Plus one practical AI-workflow email a week (no spam)

Single opt-in · unsubscribe anytime · no spam.