Skip to content

IAM API errors

[!caution]

This service is not deployed. There is no iam.shelfcs.com or sts.shelfcs.com in the published endpoint list, and no call on this page will answer. This page is the specification, not a description of something running.

For the identity system that does exist — the identity service users, one project, one role, and EC2 access keys — read Identity, as deployed.

Read this page to handle IAM errors correctly.

IAM uses the standard query error envelope, which differs from EC2’s. See IAM requests and responses for the shape.

  • None
CodeStatusTypeCause
IncompleteSignature400SenderThe Authorization header is malformed
SignatureDoesNotMatch403SenderThe signature does not match the request
InvalidClientTokenId403SenderThe access key id is unknown or inactive
MissingAuthenticationToken403SenderThe request was not signed
RequestExpired400SenderThe timestamp is outside the permitted skew
AccessDenied403SenderPolicy does not allow this action

AccessDenied is the outcome clients branch on most often, which is why it is first in this table rather than buried below the service-specific codes.

CodeStatusTypeCause
NoSuchEntity404SenderThe user, group, role, policy or key does not exist
EntityAlreadyExists409SenderA resource with that name already exists
DeleteConflict409SenderThe resource still has attachments or credentials
LimitExceeded409SenderAn account quota would be exceeded
MalformedPolicyDocument400SenderThe policy document is not valid
InvalidInput400SenderA parameter value is not acceptable
UnmodifiableEntity409SenderThe resource cannot be changed
CodeStatusTypeCauseRetry
Throttling400SenderRequest rate exceededYes, with backoff
ServiceFailure500ReceiverAn unexpected failure on our sideYes

Throttling is a 400 here and RequestLimitExceeded is a 503 in EC2. That inconsistency is inherited: each service matches the code and status its AWS counterpart returns, because client retry logic keys on both.

ServiceFailure is the code AWS IAM documents on every action for an unexpected error, so it is the code used here rather than a name of our own.

A policy that cannot be evaluated is our failure, not a denial. It returns ServiceFailure with a 500 — never AccessDenied.

The distinction matters more than it appears: reported as a denial, a customer spends a day rewriting a policy that was correct all along.

An entity in another account, or one that has never existed, returns NoSuchEntity. An entity in the caller’s own account that policy forbids returns AccessDenied. Existence is never confirmed to a caller not entitled to know it.

DeleteConflict rather than a cascading delete is deliberate. Deleting a user must not silently delete the access keys something is still authenticating with: the caller is told what remains and deletes it explicitly.