zeroclaw-labs/zeroclaw · error

No IAM role attached to this instance

Error message

No IAM role attached to this instance

What it means

The Bedrock provider's from_imds credential path queries EC2 instance metadata (169.254.169.254) for the IAM security-credentials role list. The IMDS endpoint responded (with a valid token), but the role list came back empty, meaning no instance profile is attached, so no credentials can be derived from the instance.

Solutions

  1. Attach an IAM instance profile whose role has Bedrock permissions to the instance, then re-run
  2. For containers on EC2, raise the metadata hop limit: aws ec2 modify-instance-metadata-options --instance-id i-... --http-put-response-hop-limit 2
  3. Provide explicit credentials instead (AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY or a named profile) and skip IMDS

Example fix

# before: instance without profile
aws ec2 associate-iam-instance-profile \
  --instance-id i-1234 \
  --iam-instance-profile Name=bedrock-runner-role
Defensive patterns

Strategy: fallback

Validate before calling

# probe IMDS for an attached role before relying on it
TOKEN=$(curl -sf -X PUT http://169.254.169.254/latest/api/token -H 'X-aws-ec2-metadata-token-ttl-seconds: 60') && \
ROLE=$(curl -sf http://169.254.169.254/latest/meta-data/iam/security-credentials/ -H "X-aws-ec2-metadata-token: $TOKEN") && \
[ -n "$ROLE" ] || echo 'no instance profile — attach one or use explicit credentials' >&2

Try / catch

when constructing the Bedrock provider, try IMDS credentials; on the no-IAM-role error fall back to explicit credentials (environment/profile) before giving up, and log which path succeeded

Prevention

When it happens

Trigger: EC2 (or ECS/ECR-based) workload launched without an IAM instance profile; the role was attached in IAM but not as an instance profile on the instance; containers where the metadata hop limit prevents reaching the credentials path so only an empty role list is visible; a non-AWS environment where something else answers on 169.254.169.254.

Common situations: Terraform/CloudFormation templates that create the role but forget the instance-profile association; containers on EC2 needing --http-put-response-hop-limit 2; developers assuming AWS_* env-var-less code will just work on a bare instance.

Related errors


AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23). Data as JSON: /api/errors/d1f9095622a1952f. Report an issue: GitHub.

Appendix: source

Thrown at crates/zeroclaw-providers/src/bedrock.rs:235

        // Step 1: get IMDSv2 token
        let token = client
            .put("http://169.254.169.254/latest/api/token")
            .header("X-aws-ec2-metadata-token-ttl-seconds", "21600")
            .send()
            .await?
            .text()
            .await?;

        // Step 2: get IAM role name
        let role = client
            .get("http://169.254.169.254/latest/meta-data/iam/security-credentials/")
            .header("X-aws-ec2-metadata-token", &token)
            .send()
            .await?
            .text()
            .await?;
        let role = role.trim().to_string();
        anyhow::ensure!(!role.is_empty(), "No IAM role attached to this instance");

        // Step 3: get credentials for that role
        let creds_url = format!(
            "http://169.254.169.254/latest/meta-data/iam/security-credentials/{}",
            role
        );
        let creds_json: serde_json::Value = client
            .get(&creds_url)
            .header("X-aws-ec2-metadata-token", &token)
            .send()
            .await?
            .json()
            .await?;

        let access_key_id = creds_json["AccessKeyId"]
            .as_str()
            .ok_or_else(|| {
                ::zeroclaw_log::record!(

View on GitHub (pinned to 88bb9c8533)