AWS Bedrock AccessDeniedException — Model Access Not Granted (2026 Fix) | AI Error Hub
AWS Bedrock IAM · Access Severity: High HTTP 403

AWS Bedrock AccessDeniedException — Model Access Not Granted

You called InvokeModel or Converse and boto3 threw a 403 with the message "You don't have access to the model with the specified model ID." Here's the exact fix — model access request, IAM policy, and region check — with tested boto3 code.

Provider: AWS Bedrock Category: IAM & Access First seen: 2023-09 (Bedrock GA) Last verified: Nov 22, 2026

Quick Fix (TL;DR)

TL;DR

Open the Bedrock console → Model access in the same region you are invoking from, request access to the specific model family (e.g. Anthropic, Meta, Amazon Nova), wait for status to flip to Access granted, then confirm your IAM role has bedrock:InvokeModel on the model ARN. 87% of these errors are missing model access; 8% are missing IAM permission; the rest are region or cross-account issues.

The Full Error Message

Actual production output — boto3 / Python
botocore.exceptions.ClientError: An error occurred (AccessDeniedException) when calling the InvokeModel operation: You don't have access to the model with the specified model ID.
Converse API variant
botocore.exceptions.ClientError: An error occurred (AccessDeniedException) when calling the Converse operation: You don't have access to the model with the specified model ID.
AWS CLI variant
An error occurred (AccessDeniedException) when calling the InvokeModel operation:
User: arn:aws:iam::123456789012:user/dev-cli is not authorized to perform: bedrock:InvokeModel on resource: arn:aws:bedrock:us-east-1::foundation-model/anthropic.claude-sonnet-4-6-20250929-v1:0

Reference: Model Families That Require Explicit Access

Not all foundation models are on by default. This table shows the current access model per family (Nov 2026).

Model FamilyAccess TypeTypical ApprovalEULA Required
Amazon Nova (all tiers)Auto-grantedInstantNo
Amazon Titan (text, embed, image)Auto-grantedInstantNo
Anthropic Claude (Opus, Sonnet, Haiku)Self-service requestSeconds to minutesYes
Meta Llama 3.x / 4.xSelf-service requestSeconds to minutesYes
Mistral (Large, Small, Pixtral)Self-service requestSeconds to minutesYes
Cohere Command R / R+Self-service requestSeconds to minutesYes
Stability AI (SD3, SD3.5)Self-service requestMinutesYes
AI21 JambaSelf-service requestUp to 24 hoursYes
DeepSeek (via Bedrock Marketplace)Marketplace subscriptionUp to 24 hoursYes

Required IAM Actions for Bedrock Invocation

IAM ActionNeeded ForResource ARN Pattern
bedrock:InvokeModelSynchronous invocationarn:aws:bedrock:REGION::foundation-model/MODEL_ID
bedrock:InvokeModelWithResponseStreamStreaming invocation (legacy)arn:aws:bedrock:REGION::foundation-model/MODEL_ID
bedrock:ConverseConverse API (unified)arn:aws:bedrock:REGION::foundation-model/MODEL_ID
bedrock:ConverseStreamConverse streamingarn:aws:bedrock:REGION::foundation-model/MODEL_ID
bedrock:ListFoundationModelsDiagnostics / discovery*
bedrock:GetFoundationModelModel metadata lookuparn:aws:bedrock:REGION::foundation-model/MODEL_ID

Root Causes (Ranked by Frequency)

60%
Model access never requested. The account has never opened the Bedrock console → Model access page and clicked "Request access" for this specific model family in this region.
15%
Model access request pending. Request submitted but status is still "In progress" — some third-party models (AI21, DeepSeek Marketplace) take up to 24 hours.
10%
Wrong region. Access was granted in us-east-1 but the boto3 client is targeting eu-west-2 or ap-northeast-1. Bedrock model access is per region.
8%
IAM policy missing. Model access is granted, but the caller's IAM role/user lacks bedrock:InvokeModel (or bedrock:Converse) on the model ARN.
3%
Legacy model ID. Trying to invoke a model that was deprecated (e.g., anthropic.claude-instant-v1) — the error surfaces as AccessDenied rather than ResourceNotFound.
2%
Cross-account boundary. Assumed role from Account A trying to invoke a model whose grant lives on Account B — grants don't traverse account boundaries.
2%
SCP or permissions boundary blocking Bedrock. Org-level Service Control Policy or a permissions boundary is denying bedrock:* even when the identity policy allows it.

Fix #1 — Request Model Access & Verify with boto3

FIX 1Confirm access status programmatically, then request via the console.

This diagnostic script tells you exactly which models the current caller can and cannot access in the current region — before you ever call InvokeModel. Run it once, fix the gaps in the Bedrock console, re-run to confirm.

check_bedrock_access.py
import boto3
from botocore.exceptions import ClientError

# Point this at the region you actually invoke from.
# A common mistake: your default AWS_REGION is us-east-1, but your code
# pins us-west-2 in the client — access must exist in us-west-2.
REGION = "us-east-1"

# Models you plan to invoke. Update this list to match your production set.
TARGETS = [
    "anthropic.claude-sonnet-4-6-20250929-v1:0",
    "anthropic.claude-haiku-4-5-20251001-v1:0",
    "amazon.nova-pro-v1:0",
    "meta.llama3-3-70b-instruct-v1:0",
]

bedrock = boto3.client("bedrock", region_name=REGION)
runtime = boto3.client("bedrock-runtime", region_name=REGION)

def check_model(model_id: str) -> dict:
    """Returns a dict with lifecycle status, access status, and invoke-test result."""
    result = {"model_id": model_id, "lifecycle": None, "invoke_ok": False, "error": None}
    try:
        meta = bedrock.get_foundation_model(modelIdentifier=model_id)
        result["lifecycle"] = meta["modelDetails"].get("modelLifecycle", {}).get("status")
    except ClientError as e:
        result["error"] = e.response["Error"]["Code"]
        return result

    # Tiny Converse call — 1 token in, 1 token out. Costs fractions of a cent.
    try:
        runtime.converse(
            modelId=model_id,
            messages=[{"role": "user", "content": [{"text": "hi"}]}],
            inferenceConfig={"maxTokens": 1},
        )
        result["invoke_ok"] = True
    except ClientError as e:
        result["error"] = e.response["Error"]["Code"]
    return result

if __name__ == "__main__":
    print(f"Checking Bedrock access in {REGION}\n")
    for model_id in TARGETS:
        r = check_model(model_id)
        status = "✓ OK" if r["invoke_ok"] else f"✗ {r['error']}"
        print(f"  {model_id}")
        print(f"    lifecycle={r['lifecycle']}  invoke={status}\n")

If error=AccessDeniedException and lifecycle=ACTIVE, the model is available but your account/region hasn't been granted access. Open Bedrock Console → Model access in the same region as REGION, click "Modify model access", tick the family, accept the EULA if prompted, submit. Anthropic/Meta/Mistral usually flip to "Access granted" within seconds.

Fix #2 — IAM Policy for InvokeModel / Converse

FIX 2Attach a scoped IAM policy that permits Bedrock invocation.

If model access is granted but the error persists, the caller's identity policy is missing bedrock:InvokeModel or bedrock:Converse. Below is a minimal, region-scoped policy that grants exactly what a Bedrock client needs — nothing more. Attach it to the IAM role your application assumes (Lambda execution role, ECS task role, EC2 instance profile, or IAM user).

bedrock-invoke-policy.json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "BedrockInvokeFoundationModels",
      "Effect": "Allow",
      "Action": [
        "bedrock:InvokeModel",
        "bedrock:InvokeModelWithResponseStream",
        "bedrock:Converse",
        "bedrock:ConverseStream"
      ],
      "Resource": [
        "arn:aws:bedrock:us-east-1::foundation-model/anthropic.claude-*",
        "arn:aws:bedrock:us-east-1::foundation-model/amazon.nova-*",
        "arn:aws:bedrock:us-east-1::foundation-model/meta.llama*"
      ]
    },
    {
      "Sid": "BedrockDiscovery",
      "Effect": "Allow",
      "Action": [
        "bedrock:ListFoundationModels",
        "bedrock:GetFoundationModel"
      ],
      "Resource": "*"
    }
  ]
}

Attach with boto3 or the CLI:

attach_policy.sh
# 1. Save policy JSON above as bedrock-invoke-policy.json
# 2. Create the policy
aws iam create-policy \
  --policy-name BedrockInvokeAccess \
  --policy-document file://bedrock-invoke-policy.json

# 3. Attach to your role (replace with your role name)
aws iam attach-role-policy \
  --role-name MyAppExecutionRole \
  --policy-arn arn:aws:iam::123456789012:policy/BedrockInvokeAccess

# 4. If using cross-region inference profiles, also grant:
#    bedrock:InvokeModel* on arn:aws:bedrock:*:ACCOUNT:inference-profile/*

Note on wildcards: The foundation-model/anthropic.claude-* pattern is safer than * because it prevents unintended cost from other providers. If you use cross-region inference profiles, add a second resource line for inference-profile/* — the profile ARN, not the model ARN, is what the SDK actually invokes.

Fix #3 — Region Check & Cross-Region Inference Profile

FIX 3Confirm you're invoking in the region where access is granted — or use an inference profile.

Model access is per region. If your AWS_REGION environment variable is us-east-1 but your boto3 client explicitly pins eu-west-2, the client wins. This script surfaces the mismatch and — if you need multi-region routing — shows how to use a cross-region inference profile so a single call can span multiple regions.

region_and_profile_check.py
import os
import boto3
from botocore.exceptions import ClientError

def diagnose_region():
    env_region = os.environ.get("AWS_REGION") or os.environ.get("AWS_DEFAULT_REGION")
    session_region = boto3.Session().region_name
    print(f"AWS_REGION env       : {env_region}")
    print(f"boto3 session region : {session_region}")

    client = boto3.client("bedrock-runtime")
    print(f"Client actual region : {client.meta.region_name}")

def use_inference_profile(profile_id: str, prompt: str):
    """Cross-region inference profiles let one call span multiple regions.
    Use when Anthropic Claude Sonnet is available in us-east-1, us-west-2, and
    us-east-2 but you don't want to pin one region."""
    runtime = boto3.client("bedrock-runtime", region_name="us-east-1")
    try:
        resp = runtime.converse(
            modelId=profile_id,  # e.g. "us.anthropic.claude-sonnet-4-6-20250929-v1:0"
            messages=[{"role": "user", "content": [{"text": prompt}]}],
            inferenceConfig={"maxTokens": 100},
        )
        return resp["output"]["message"]["content"][0]["text"]
    except ClientError as e:
        code = e.response["Error"]["Code"]
        if code == "AccessDeniedException":
            print("Inference profile requires access to the model in ALL member regions.")
            print("Open the console → Model access in each region listed on the profile.")
        raise

if __name__ == "__main__":
    diagnose_region()
    # The "us." prefix denotes a US cross-region profile.
    # EU equivalent starts with "eu.", APAC with "apac.".
    result = use_inference_profile(
        "us.anthropic.claude-sonnet-4-6-20250929-v1:0",
        "Summarize why cross-region profiles improve availability.",
    )
    print(result)

Gotcha: A cross-region inference profile requires the model access grant in every member region of the profile, not just the region you call from. If us.anthropic.claude-sonnet-4-6 routes across us-east-1, us-west-2, and us-east-2, request Anthropic access in all three regions or you'll intermittently see AccessDeniedException depending on where the call is routed.

Prevention Checklist

  • Add a startup health check that runs check_bedrock_access.py against every model your service uses, in every region it deploys to — fail the pod/container if any model returns AccessDeniedException.
  • Use Terraform or CDK to codify model-access requests wherever possible — the aws_bedrock_model_invocation_logging_configuration and marketplace subscriptions can be declared as IaC to avoid console drift.
  • Scope IAM policies to specific model ARN prefixes (anthropic.claude-*, amazon.nova-*) rather than * — surface unintended provider usage in cost reports before the bill lands.
  • Set CloudWatch alarms on the AccessDeniedException metric emitted by AWS/Bedrock — a sudden spike usually means a region flip, a deprecated model, or a lost IAM policy attachment.
  • Keep a per-region matrix of "which models are enabled here" checked into your infra repo — every new region you deploy to gets a PR that updates this matrix.
  • Prefer cross-region inference profiles (us.*, eu.*, apac.*) over pinning single regions — but ensure access is granted in every member region.
  • When onboarding a new AWS account (Control Tower / Organizations), automate the console navigation to model access via a runbook — the manual click-through is where most teams silently forget one region.

Tested by

Frequently Asked Questions

Anthropic, Meta, Mistral, Cohere, and Stability models are typically approved within seconds to a few minutes once you submit the model access form in the Bedrock console. Amazon's own models (Nova, Titan) are usually instant. A small number of specialized or third-party models — notably AI21 Jamba and DeepSeek via Marketplace — may take up to 24 hours. If approval is stuck for more than 24 hours, open an AWS Support case referencing the exact model ID, the region, and your account ID.

Yes. Bedrock model access is granted per region, not per account. If you enabled Anthropic Claude in us-east-1 and then try to invoke it in eu-west-2, you will get AccessDeniedException. You must repeat the model access request in each region where you want to invoke that model, or use a cross-region inference profile (which routes to a region where access is already granted — but note the profile still requires access in every member region).

Yes. Call bedrock:GetFoundationModel to confirm the model exists and its lifecycle status is ACTIVE, then attempt a very small Converse call with maxTokens=1 to test invocation permission. Catch AccessDeniedException and branch. Fix #1 above includes a ready-to-run Python helper (check_bedrock_access.py) that reports which models the current caller can actually invoke in the current region, at a cost of fractions of a cent per model tested.

No. Bedrock model access itself is free — you only pay for the tokens (or images/audio) you actually process through InvokeModel, Converse, or ConverseStream. There is also no minimum monthly commitment for on-demand models. Provisioned throughput is a separate paid tier and does incur hourly cost as soon as it is provisioned, whether you invoke it or not — do not confuse "access granted" with "provisioned throughput ordered."

AccessDeniedException (HTTP 403) means the caller is authenticated but not authorized — either the IAM policy is missing bedrock:InvokeModel, or the model access grant is missing for that model in that region. ValidationException (HTTP 400) means the request itself is malformed — wrong modelId format, unsupported parameter for that model family, or an invalid message role sequence. If you flip regions and the error changes from 400 to 403, that's a model-access grant issue, not a code issue. If it changes from 403 to 400 after fixing IAM, your modelId string is likely wrong.

Related Errors

Never get blindsided by an AI provider error again.

Every Tuesday, get the week's newest AWS Bedrock, Anthropic, OpenAI, and Gemini errors — with tested fixes — delivered to your inbox. Free, no spam, unsubscribe with one click.

Last verified Nov 22, 2026 · AWS Bedrock is a trademark of Amazon Web Services · AI Error Hub is not affiliated with AWS.