skip to content

In Jenkins, what do the credential scopes System, Global and User control, and why can a job report "Could not find credentials entry with ID" for an ID an administrator can plainly see?

level: middleimportance: should knowfreq 45%

answer

  1. store answers where, scope answers who
  2. System is for Jenkins itself
  3. jobs resolve upward through ancestry
  4. folders bound the blast radius
  5. domains filter by hostname or scheme

basics

~20 s

Scope decides who may use a Jenkins credential: System means the controller itself only (agent launches, cloud configuration) and is invisible to jobs; Global means the storing object and its children; User means one person's private store. A System-scoped entry produces the "not found" error in a build.

solid answer

~50 s

Every Jenkins credential carries a **scope** alongside its ID and kind. `System` means only Jenkins itself may use it — connecting an agent over SSH, authenticating a cloud plugin — and jobs cannot see it at all. `Global` means it is available to the object that stores it and everything beneath, which is what a pipeline needs. `User` means it lives in one user's personal store and is only usable in contexts where that user is the authenticated actor. Separately, credentials live in a **store**: the Jenkins root store, a Folder's store, or a user's store, and a job only sees the stores in its own ancestry. So the "not found" error usually means one of three things: the entry is System-scoped, it sits in a different folder's store than the job, or the ID is simply mistyped. Domains add a further filter, restricting an entry to matching hostnames or schemes.

go deeper

for a junior

Know that a credential has a scope as well as an ID, and that a build can only use Global-scoped entries stored on the job or one of its parent folders.

for a middle

Explain all three scopes, describe how resolution walks the item ancestry, and debug the "not found" error in order: scope, store, ID, domain, kind.

for a senior

Show that you use folder stores to bound which pipelines can name which secrets, and that you keep infrastructure credentials System-scoped so no Jenkinsfile can reach them.

for a principal

Own the layout decision across teams: how many controllers, which secrets are allowed on a shared one at all, and how credential placement maps onto your authorization model rather than fighting it.

## Two independent axes: store and scope People conflate them, and the conflation is what produces the confusing error. A credential is identified by **where it is stored** and **how widely it may be used from there**. **Store** answers "which part of the Jenkins object tree owns this entry?" There is a store on the Jenkins root, a store on every Folder (from the Folders plugin), and a private store per user. An item resolves a credential ID by walking *up* its own ancestry: a job inside the folder `/team-a` can use entries from that folder's store, from any parent folder's store, and from the root store. It cannot see `/team-b`'s store, ever. That containment is the main tool you have for stopping one team's pipelines from using another team's deploy key. **Scope** answers "which kinds of consumer may use this entry from that store?" Three values exist: - **System** — usable only by Jenkins core and plugin configuration running as the system: launching an agent over SSH, a cloud plugin authenticating to a provider, a globally configured notifier. Builds cannot enumerate or bind System credentials. This exists precisely so an infrastructure credential cannot be pulled into someone's Jenkinsfile. - **Global** — usable by the object that holds it and everything below it, including builds. This is the scope a pipeline binding needs. - **User** — stored in a person's own credentials store and usable where that person is the authenticated actor, for example their own personal configuration. It is not the scope for a shared deploy key. ## Debugging the "not found" error When `withCredentials` or `credentials('id')` fails with `Could not find credentials entry with ID '...'`, work through this order: 1. **Scope.** Open the entry. If it says System, a job will never see it, no matter who is running the build. Either create a Global-scoped copy for the job, or reconsider whether the job should have it at all. 2. **Store.** Is it in the root store, or in a folder that is *not* an ancestor of this job? Moving a job between folders quietly changes which credentials resolve — a common cause of "it worked before we reorganised". 3. **ID.** Typos and case differences. The ID is an opaque string; nothing validates it until the build runs. 4. **Domain.** If the entry sits in a non-global domain that restricts hostnames or schemes, a plugin that filters by domain may not offer it for the URL in question, even though the ID exists. 5. **Kind mismatch.** Binding a username/password entry with `string(...)` fails; the descriptor must match the kind. The message differs, but the debugging instinct is the same. ## Why scope is a security control, not bookkeeping The interesting property of System scope is that it survives an untrustworthy Jenkinsfile. Anyone who can edit a job's pipeline can bind any *Global* credential visible from that job's position in the tree — the ID is all you need, and a build can exfiltrate a value it can read. System scope removes an entire class of credential (the ones that let Jenkins talk to its own infrastructure) from that reach. The same reasoning drives folder scoping. Instead of one root store holding every secret in the organisation — where every job can name every ID — you push each team's credentials into their folder. A job in `/payments` then physically cannot resolve `marketing-mailer-key` if that entry lives only in `/marketing`, regardless of what its Jenkinsfile says. ## Practical layout A workable arrangement on a shared controller: - Root store: nothing but genuinely universal, low-value entries; infrastructure entries kept **System**-scoped. - One folder per team, each with its own Global-scoped credentials, and folder-level permissions that match. - Production deploy credentials in a separate folder — or a separate controller entirely — with a much shorter list of people who can create or configure jobs there. - User-scoped credentials left for genuinely personal use; not a mechanism for sharing. Nothing here prevents a person who can *configure* a job in a folder from reading that folder's credentials — scoping bounds the blast radius, it does not eliminate it. Pair it with an authorization strategy that keeps job configuration rights narrow.

  • Why would you deliberately keep an agent's SSH credential System-scoped rather than Global?
    Because Global entries are bindable by any pipeline that can see the store, and anyone able to edit a Jenkinsfile can print or exfiltrate what they bind. System scope makes the entry usable by the controller's own agent-launch machinery while being invisible to builds, so a compromised or careless job cannot reach the credential that connects your fleet.
  • A job moved from one folder to another and suddenly cannot find a credential. What changed?
    Credential resolution walks the item's ancestry, so a job only sees stores on itself, its parent folders, and the root. Moving it out of the folder that held the entry removes that store from the path. The fix is to place the credential in a store the job's new position can reach — usually the new folder, or a shared parent — rather than falling back to the root store for everything.
  • What does a credentials domain add on top of scope?
    A domain attaches specification rules such as hostname or scheme to a set of entries, so domain-aware plugins only offer matching credentials for a given URL. It is an ergonomics and mistake-prevention feature — it keeps a staging password from being offered for a production host — not an authorization boundary, since a pipeline can still bind by ID.

saying these in an interview costs you the question

  • Treating scope as a label rather than an enforced boundary
  • Putting every credential in the root store for convenience
  • Assuming User scope is how you share a credential with a team
  • Believing folder scoping stops someone who can configure jobs in that folder
  • Blaming an ID typo without checking scope or store

context