Silicon IAMDocs

Errors

Match the error variant first, then match a service error's stable code; never branch on human-readable prose.

The taxonomy

VariantMeansRecovery
Error::InvalidA local value cannot form a request, such as an invalid URL, environment key or idempotency key.Fix the input; do not retry it unchanged.
Error::ApiVersionUnsupportedThe service offers no API major this crate implements.Upgrade the client or correct the service target.
Error::TransportNo complete response arrived because of a connection, TLS, timeout, or failure while reading the response.The outcome may be unknown. A mutation may be retried only with its original Mutation.
Error::DecodeA response arrived but its body did not match the expected contract, or negotiation invariants disagreed.Do not blindly retry. Retain the mutation key and request ID, then investigate a client/service compatibility bug.
Error::UnstructuredResponseAn HTTP failure arrived without IAM's error envelope, for example an edge-generated HTML 403. This does not establish an IAM authorization decision.Check the service URL and edge/proxy logs using the HTTP status and optional response request ID. Do not retry blindly or assume another login will fix it.
Error::ResponseTooLargeA response body exceeded the fixed 4 MiB client bound, whether or not it declared a length first.Do not blindly retry. Retain the mutation key and investigate the service or intermediary response.
Error::ApiIAM returned its structured error envelope. Use the status, stable code and classifiers on ApiError.
Error::RateLimitedIAM returned 429; the variant holds the retry delay, optional counts and service envelope.Wait at least retry_after, then resend unchanged with the same mutation when applicable.

Reading an API error

use silicon_iam_client::{Error, Mutation};

let refreshing = Mutation::new();
match application
    .oauth()
    .refresh(app_id, refresh_token, &refreshing)
    .await
{
    Ok(replacement) => { /* store it atomically */ }
    Err(Error::Api(api)) => {
        eprintln!("IAM {} {} request={:?}",
            api.status, api.code, api.request_id);

        if api.is_version_conflict() {
            // Re-read the resource before deciding on a new mutation.
        } else if api.requires_step_up() {
            // Complete step-up for the documented action and resource UUID.
        }
    }
    Err(Error::RateLimited { retry_after, source, .. }) => {
        eprintln!("wait {:?}; request={:?}", retry_after, source.request_id);
    }
    Err(other) => return Err(other),
}

ApiError exposes status, code, message, optional details, and optional request_id. Helpers classify unauthenticated, forbidden, hidden/not-found, version conflict, step-up, idempotency conflict and retryable service responses. The outer Error::request_id() and Error::api() work for both ordinary API and rate-limit errors.

Error::UnstructuredResponse retains the observed HTTP status and a well-formed UUID X-Request-Id when present; Error::request_id() exposes that correlation hint, while Error::api() returns None. The client does not retain or print HTML, other raw error bodies, or arbitrary response headers. A missing request ID remains missing: neither a status nor a proxy-branded page identifies a particular firewall rule or proves whether the backend processed the operation.

Retry and recovery

Transport guardrails

Client construction requires HTTPS except for literal local loopbacks and rejects service URLs with embedded credentials, a zero port, query, fragment, or no host. Requests never follow a redirect, so a credential is not forwarded away from the configured IAM endpoint. The 4 MiB response bound is enforced while streaming as well as from Content-Length.

What to log

LogDo not log
Request ID, status, stable code, operation name, your correlation ID, and the idempotency key identifier when your policy permits it Access, refresh, short-lived or OBO tokens; Application client or webhook secrets; testing root keys; raw callback query strings; successful secret-bearing response models

Credential wrapper types redact their secret material from Debug, but successful response models deliberately expose values your application must store. Do not infer that every arbitrary string or model is safe to log.