GoogleContainerTools/jib · error · IllegalStateException
push may fail with pull-only bearer auth token
Error message
push may fail with pull-only bearer auth token
What it means
RegistryClient.pushManifest refuses to push a manifest when the client is using Bearer authentication with a token that was obtained with pull-only (read-only) scopes. Since the token lacks push scope, the push would fail at the registry, so Jib fails fast with IllegalStateException.
Source
Thrown at jib-core/src/main/java/com/google/cloud/tools/jib/registry/RegistryClient.java:454
public ManifestAndDigest<ManifestTemplate> pullManifest(String imageQualifier)
throws IOException, RegistryException {
return pullManifest(imageQualifier, ManifestTemplate.class);
}
/**
* Pushes the image manifest for a specific tag.
*
* @param manifestTemplate the image manifest
* @param imageTag the tag to push on
* @return the digest of the pushed image
* @throws IOException if communicating with the endpoint fails
* @throws RegistryException if communicating with the endpoint fails
*/
public DescriptorDigest pushManifest(ManifestTemplate manifestTemplate, String imageTag)
throws IOException, RegistryException {
if (isBearerAuth(authorization.get()) && readOnlyBearerAuth) {
throw new IllegalStateException("push may fail with pull-only bearer auth token");
}
return callRegistryEndpoint(
new ManifestPusher(
registryEndpointRequestProperties, manifestTemplate, imageTag, eventHandlers));
}
/**
* Check if a blob is on the registry.
*
* @param blobDigest the blob digest to check for
* @return the BLOB's {@link BlobDescriptor} if the BLOB exists on the registry, or {@link
* Optional#empty()} if it doesn't
* @throws IOException if communicating with the endpoint fails
* @throws RegistryException if communicating with the endpoint fails
*/
public Optional<BlobDescriptor> checkBlob(DescriptorDigest blobDigest)
throws IOException, RegistryException {View on GitHub (pinned to fb949e2676)
Solutions
- Obtain a RegistryClient via a factory that requests push scopes (e.g., RegistryClient.factory(...).setCredential... / toOtherRepository with push intent) so the token is requested with pull,push scope
- Use credentials/token with push permissions (service account or IAM role granting write)
- If you only intend to pull, do not call pushManifest on this client
Example fix
// before: read-only client used for push RegistryClient client = new RegistryClient(credential, serverUrl, imageName, eventHandlers); client.configureReadOnlyBearerAuth(); client.pushManifest(manifest, tag); // after: client authorized for push RegistryClient client = new RegistryClient(credential, serverUrl, imageName, eventHandlers); // token fetched with push scope client.pushManifest(manifest, tag);
Defensive patterns
Strategy: validation
Validate before calling
// ensure the token has push scope before attempting a push // (Jib guards this internally; pre-validate your service account's scopes in CI) assertPushScopeGranted(registry, serviceAccount);
Try / catch
try { client.pushManifest(manifest, tag); } catch (IllegalStateException e) { // client is pull-only; obtain a push-scoped client
newPushScopedClient().pushManifest(manifest, tag); } Prevention
- Use one client per intent: pull clients for pulls, push-scoped for pushes
- Verify service accounts/IAM roles grant write before CI push jobs
- Do not combine configureReadOnlyBearerAuth with push calls
When it happens
Trigger: Calling pushManifest (or constructing a RegistryClient via factory methods like toOtherRepository) on a client whose authorization is Bearer and readOnlyBearerAuth is true — i.e., the token was fetched without push (pull,push) repository scopes.
Common situations: Building/pushing using a registry client initialized for pulling (e.g., toOtherRegistry/pull-oriented API) and then attempting to push; using an access token scoped read-only; misconfigured service account/token with only pull permissions (e.g., GCR pull-only service account).
Understand the failure class
Background: "You do not have permission" / 403 Forbidden errors: authenticated but not allowed — causes and fixes across open-source libraries — this error's family across 31 libraries.
Related errors
- Expected image digest ${expectedDigest}, but received: ${rec
- Received unrecognized status code ${statusCode}
- Expected 1 'Location' header, but found ${headerCount}
- Cannot build to a container registry in offline mode
- Invalid container configuration in Docker V2.2/OCI manifest:
AI-assisted analysis of GoogleContainerTools/jib@fb949e2676 (2026-09-06).
Data as JSON: /api/errors/f0dacf68674df3f1.
Report an issue: GitHub.