Use AWS (Amazon Bedrock)
If your company runs on AWS, the models that are easiest to get approved are often the ones already inside your AWS account. Amazon Bedrock runs models from DeepSeek, Mistral, OpenAI, Anthropic and others there. The bill arrives with the rest of AWS, the same permissions decide who may call them, and the requests stay in the region you choose. The catch is that Bedrock offers several APIs, and which one a model answers on decides how you reach it.
LM15 reaches Bedrock through the provider bedrock-chat, and two neighbors
we’ll meet later. The request is the one you already know. What’s new is who
signs in, which region the request runs in, and how Bedrock names its
models.
On this page, we’ll start with the setup in your AWS account. Then we’ll send a question from a laptop, ask LM15 where it found the sign-in, and choose a region on purpose. Next, we’ll look at how Bedrock names models, and at Claude, which works differently. We’ll finish on an EC2 instance, with an API key, and with the mistakes that cost people the most time.
You’ll need an AWS account and the aws command-line tool, which AWS’s
install guide
explains. Every request on this page costs a fraction of a cent.
Set up your account
Section titled “Set up your account”There’s less to set up on Bedrock than on the other clouds. Most models are ready to use as soon as your account can call Bedrock at all. Two things can still stand in the way.
The first is permission. A person with administrator access can call every
model. A program usually runs with less, and needs the
bedrock:InvokeModel and bedrock:InvokeModelWithResponseStream actions.
Those two were all the EC2 instance in Run on AWS was allowed,
and they were enough for bedrock-chat.
The second is the model itself. Some model makers ask for more before their models answer. The first time someone in an account uses one of Anthropic’s models, for example, AWS asks for a short description of the use case in the Bedrock console. And AWS can refuse an account anyway, as it did ours for Claude. We’ll see that error later on.
Sign in on your laptop
Section titled “Sign in on your laptop”Sign in with the aws tool, the way your organization does it:
aws configure sso and then aws sso login if you use IAM Identity Center,
aws login if you sign in with your console password, or aws configure
with an access key. LM15 reads what each of these saves, the way AWS’s own
libraries do. Then choose a region:
aws configure set region us-east-1That’s all LM15 needs. The examples in these guides follow one small program: an assistant for a wildlife research station. Here’s its first question, sent to DeepSeek V3.2 on Bedrock:
from lm15 import LMRouter, Message, Request
router = LMRouter()request = Request( model="bedrock-chat:deepseek.v3.2", system=( "You are the field assistant for a wildlife research " "station. Answer in two sentences." ), messages=[Message.user( "What might be eating the acorns under our oak trees at " "night?" )],)print(router.complete(request).text)Several nocturnal animals could be responsible for eating the acorns under your oak trees. The most likely culprits are rodents like squirrels (which can be active at night), raccoons, opossums, and deer, which often forage after dark. To confirm, you could look for tracks, scat, or set up a motion-activated camera.
import { LMRouter, Message } from "@lm15/lm15";
const router = new LMRouter();const request = { model: "bedrock-chat:deepseek.v3.2", system: "You are the field assistant for a wildlife research station. " + "Answer in two sentences.", messages: [Message.user( "What might be eating the acorns under our oak trees at night?", )],};const response = await router.complete(request);console.log(response.text);Several nocturnal animals could be responsible. Likely candidates include raccoons, opossums, deer, wild turkeys, and squirrels—some of which are active well after dark as they forage for food.
use lm15::{LMRouter, Message, Request};
// Dependencies: lm15, tokio (macros, rt-multi-thread)#[tokio::main]async fn main() -> Result<(), Box<dyn std::error::Error>> { let router = LMRouter::new(); let request = Request { model: "bedrock-chat:deepseek.v3.2".into(), system: Some(concat!( "You are the field assistant for a wildlife research ", "station. Answer in two sentences.", ).into()), messages: vec![Message::user(concat!( "What might be eating the acorns under our oak trees at ", "night?", ))?], ..Default::default() }; let response = router.complete(&request).await?; println!("{}", response.text().unwrap_or_default()); Ok(())}Likely suspects include raccoons, deer, or wild turkeys, as they are all nocturnal or crepuscular feeders known to consume acorns. You could set up a wildlife camera to confirm which animal is visiting your oak trees.
package main
import ( "context" "fmt" lm15 "github.com/lm15-dev/lm15-go/v2")
func main() { router := lm15.NewRouter() request := &lm15.Request{ Model: "bedrock-chat:deepseek.v3.2", System: lm15.System( "You are the field assistant for a wildlife research " + "station. Answer in two sentences.", ), Messages: []lm15.Message{ lm15.UserMessage( "What might be eating the acorns under our oak trees " + "at night?", ), }, } response, err := router.Complete(context.Background(), request) if err != nil { panic(err) } fmt.Println(response.TextOr(""))}Based on local wildlife, raccoons and opossums are the most common nocturnal acorn predators in our area. Squirrels may also be active at the tree base in the early evening or pre-dawn hours, and deer could be visiting overnight as well.
This page has no R example yet: choose Python, TypeScript, Rust or Go above.
This page has no Julia example yet: choose Python, TypeScript, Rust or Go above.
The model string bedrock-chat:deepseek.v3.2 names the provider,
bedrock-chat, and Bedrock’s ID for the model. Nothing in the program names
an account, a key or a region. LM15 found the sign-in and the region where
the aws tool saved them. (Our test machine signed in with an access key.)
Ask where the sign-in came from
Section titled “Ask where the sign-in came from”A program that finds its sign-in on its own should be able to say where. The doctor answers that question without sending anything:
from lm15.doctor import explain_auth
print(explain_auth("bedrock-chat"))auth for provider 'bedrock-chat': - explicit api_keys entry: not provided - env $AWS_BEARER_TOKEN_BEDROCK: not set - env $AWS_ACCESS_KEY_ID (+SECRET, +SESSION_TOKEN): AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY not set - profile assume-role via STS: profile 'default' has no role_arn with a source - web identity via STS: AWS_WEB_IDENTITY_TOKEN_FILE / AWS_ROLE_ARN not set - IAM Identity Center (~/.aws/sso/cache): no sso_session / sso_start_url in the profile => ~/.aws/credentials: profile 'default' (values never shown) - aws login session (~/.aws/login/cache): no login_session in the profile - profile credential_process: no credential_process in the profile - ~/.aws/config static keys: no static keys in config - container credentials endpoint: no AWS_CONTAINER_CREDENTIALS_* URI ~ EC2 instance metadata (IMDSv2): instance metadata probed at request time configured: yes — ~/.aws/credentials setting region: us-east-1 (from the active AWS profile) base url: https://bedrock-runtime.us-east-1.amazonaws.com/openai/v1 (from template)
import { describeReport, explainAuth } from "@lm15/lm15";
console.log(describeReport(explainAuth("bedrock-chat")));auth for provider "bedrock-chat": - explicit api_keys entry: not provided - env $AWS_BEARER_TOKEN_BEDROCK: not set - env $AWS_ACCESS_KEY_ID (+SECRET, +SESSION_TOKEN): AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY not set - profile assume-role via STS: profile 'default' has no role_arn with a source - web identity via STS: AWS_WEB_IDENTITY_TOKEN_FILE / AWS_ROLE_ARN not set - IAM Identity Center (~/.aws/sso/cache): no sso_session / sso_start_url in the profile => ~/.aws/credentials: profile 'default' (values never shown) - aws login session (~/.aws/login/cache): no login_session in the profile - profile credential_process: no credential_process in the profile - ~/.aws/config static keys: no static keys in config - container credentials endpoint: no AWS_CONTAINER_CREDENTIALS_* URI ~ EC2 instance metadata (IMDSv2): instance metadata probed at request time base URL: https://bedrock-runtime.us-east-1.amazonaws.com/openai/v1 (template) configured: yes — ~/.aws/credentials setting region: us-east-1 (from the active AWS profile)
use lm15::auth::explain_auth;
fn main() -> Result<(), Box<dyn std::error::Error>> { let report = explain_auth("bedrock-chat", &Default::default())?; println!("{}", report.describe()); Ok(())}auth for provider "bedrock-chat": - explicit api_keys entry: not provided - env $AWS_BEARER_TOKEN_BEDROCK: not set - env $AWS_ACCESS_KEY_ID (+SECRET, +SESSION_TOKEN): AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY not set - profile assume-role via STS: profile "default" has no role_arn with a source - web identity via STS: AWS_WEB_IDENTITY_TOKEN_FILE / AWS_ROLE_ARN not set - IAM Identity Center (~/.aws/sso/cache): no sso_session / sso_start_url in the profile => ~/.aws/credentials: profile "default" (values never shown) - aws login session (~/.aws/login/cache): no login_session in the profile - profile credential_process: no credential_process in the profile - ~/.aws/config static keys: no static keys in config - container credentials endpoint: no AWS_CONTAINER_CREDENTIALS_* URI ~ EC2 instance metadata (IMDSv2): instance metadata probed at request time configured: yes — ~/.aws/credentials setting region: us-east-1 (from the active AWS profile) base url: https://bedrock-runtime.us-east-1.amazonaws.com/openai/v1 (from template)
package main
import ( "fmt" lm15 "github.com/lm15-dev/lm15-go/v2")
func main() { report, err := lm15.ExplainAuth( "bedrock-chat", lm15.ExplainOptions{}, ) if err != nil { panic(err) } fmt.Println(report.Describe())}auth for provider "bedrock-chat": - explicit api_keys entry: not provided - env $AWS_BEARER_TOKEN_BEDROCK: not set - env $AWS_ACCESS_KEY_ID (+SECRET, +SESSION_TOKEN): AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY not set - profile assume-role via STS: profile "default" has no role_arn with a source - web identity via STS: AWS_WEB_IDENTITY_TOKEN_FILE / AWS_ROLE_ARN not set - IAM Identity Center (~/.aws/sso/cache): no sso_session / sso_start_url in the profile => ~/.aws/credentials: profile "default" (values never shown) - aws login session (~/.aws/login/cache): no login_session in the profile - profile credential_process: no credential_process in the profile - ~/.aws/config static keys: no static keys in config - container credentials endpoint: no AWS_CONTAINER_CREDENTIALS_* URI ~ EC2 instance metadata (IMDSv2): instance metadata probed at request time configured: yes — ~/.aws/credentials setting region: us-east-1 (from the active AWS profile) base url: https://bedrock-runtime.us-east-1.amazonaws.com/openai/v1 (from template)
This page has no R example yet: choose Python, TypeScript, Rust or Go above.
This page has no Julia example yet: choose Python, TypeScript, Rust or Go above.
The report lists every place LM15 looks for AWS credentials, in the order
AWS’s own libraries look. A - means nothing is there, and => marks the
place LM15 will use, which here is the access key that aws configure saved
in ~/.aws/credentials. The last place, the EC2 instance metadata, only
exists on AWS’s own machines. It’s marked ~ because it would be asked only if
everything above it came up empty, and something above it didn’t.
The last two lines say where the request would go. The region, us-east-1,
came from the profile, and the address is Bedrock’s server in that region. Run the doctor whenever a request seems to use an
account or a region you didn’t expect. It prints no secret, so it’s safe to
paste into a bug report.
Choose a region
Section titled “Choose a region”The region decides which data centers process your requests, which models you can use, and what you pay for them. LM15 has no default region, because a wrong guess could send your data to a country you never chose. It looks in these places, and the first one that names a region wins:
- The router’s settings, if your program gives a region.
- The
AWS_REGIONenvironment variable, thenAWS_DEFAULT_REGION. - The region in your
awsprofile.
This matters more than it seems. Here’s the first program again, run with
AWS_REGION=ca-central-1, Canada’s region:
UnsupportedModelError: The provided model identifier is invalid. (bedrock-chat, HTTP 400, request df74e22e-84ed-417d-84e3-1971d76b1ecc)
UnsupportedModelError: The provided model identifier is invalid.
Error: UnsupportedModelError(ErrorMeta { message: "The provided model identifier is invalid.", provider: Some("bedrock-chat"), provider_code: Some("validation_error"), status: Some(400), request_id: Some("a96c4c56-e305-4f83-83df-382fead84c32"), retry_after: None, rate_limit_headers: DiagnosticHeaders({}), content_type: Some("application/json"), body_excerpt: Some("{\"error\":{\"message\":\"The provided model identifier is invalid.\",\"type\":\"invalid_request_error\",\"param\":null,\"code\":\"validation_error\"}}"), credential_source: None, feature: None })panic: The provided model identifier is invalid. (bedrock-chat, HTTP 400, request 4eb473b1-e338-43cf-a752-9acc2e56d5e2)
This page has no R example yet: choose Python, TypeScript, Rust or Go above.
This page has no Julia example yet: choose Python, TypeScript, Rust or Go above.
Canada Central doesn’t offer DeepSeek V3.2 through this API, and Bedrock’s
way of saying so is that the model ID is invalid, although there’s nothing
wrong with the ID. So before you check a model ID for typos, check which
region the request went to. The doctor’s setting region line shows the
region and where it came from.
When the region is part of a rule your program must follow, put it in the program:
from lm15 import LMRouter, Message, Request, RouterConfig
router = LMRouter(RouterConfig( settings={"bedrock-chat": {"region": "us-east-1"}},))request = Request( model="bedrock-chat:deepseek.v3.2", system=( "You are the field assistant for a wildlife research " "station. Answer in two sentences." ), messages=[Message.user( "What might be eating the acorns under our oak trees at " "night?" )],)print(router.complete(request).text)Several nocturnal animals could be responsible. Likely candidates include raccoons, squirrels (which are active at night), deer, and possibly opossums or wild turkeys.
import { LMRouter, Message } from "@lm15/lm15";
const router = new LMRouter({ settings: { "bedrock-chat": { region: "us-east-1" } },});const request = { model: "bedrock-chat:deepseek.v3.2", system: "You are the field assistant for a wildlife research station. " + "Answer in two sentences.", messages: [Message.user( "What might be eating the acorns under our oak trees at night?", )],};const response = await router.complete(request);console.log(response.text);Acorns are commonly eaten at night by nocturnal mammals in many regions. In North America, potential culprits include squirrels (which are active at dawn and dusk), raccoons, opossums, deer, and wild turkeys (though turkeys are diurnal).
use lm15::{LMRouter, Message, Request, RouterConfig};
// Dependencies: lm15, tokio (macros, rt-multi-thread)#[tokio::main]async fn main() -> Result<(), Box<dyn std::error::Error>> { let config = RouterConfig::new() .setting("bedrock-chat", "region", "us-east-1"); let router = LMRouter::with_config(config)?; let request = Request { model: "bedrock-chat:deepseek.v3.2".into(), system: Some(concat!( "You are the field assistant for a wildlife research ", "station. Answer in two sentences.", ).into()), messages: vec![Message::user(concat!( "What might be eating the acorns under our oak trees at ", "night?", ))?], ..Default::default() }; let response = router.complete(&request).await?; println!("{}", response.text().unwrap_or_default()); Ok(())}Many animals could be foraging for acorns at night. Likely culprits include raccoons, squirrels (which are active at dawn and dusk), deer, possums, and rodents like mice or voles.
package main
import ( "context" "fmt" lm15 "github.com/lm15-dev/lm15-go/v2")
func main() { router, err := lm15.NewRouterWithConfig(lm15.RouterConfig{ Settings: map[string]map[string]string{ "bedrock-chat": {"region": "us-east-1"}, }, }) if err != nil { panic(err) } request := &lm15.Request{ Model: "bedrock-chat:deepseek.v3.2", System: lm15.System( "You are the field assistant for a wildlife research " + "station. Answer in two sentences.", ), Messages: []lm15.Message{ lm15.UserMessage( "What might be eating the acorns under our oak trees " + "at night?", ), }, } response, err := router.Complete(context.Background(), request) if err != nil { panic(err) } fmt.Println(response.TextOr(""))}Two likely culprits are nocturnal rodents like squirrels or raccoons, which often carry acorns away, and deer, which may browse on them directly at night. You could look for telltale signs: scattered shell fragments and teeth marks from squirrels, or larger trampled areas and hoof prints indicating deer activity.
This page has no R example yet: choose Python, TypeScript, Rust or Go above.
This page has no Julia example yet: choose Python, TypeScript, Rust or Go above.
We ran this with AWS_REGION=ca-central-1 still set, and it answered from
us-east-1, because the router’s settings come first. On a laptop, let the
aws profile hold the region. In production, set AWS_REGION, or put the
region in the code when it must never change.
Choose a model
Section titled “Choose a model”Bedrock names models with IDs such as deepseek.v3.2 or
mistral.mistral-large-3-675b-instruct, which give the maker, a dot, and
then the model. You can find them in the Bedrock console’s model catalog, or
with
aws bedrock list-foundation-models. Not every model in that list answers on
the API bedrock-chat uses. When we sent a short request to every text model
Bedrock listed in us-east-1, in September 2026, 34 answered; most of the
others, including Amazon’s own Nova models, answer only on Bedrock’s native
API, which LM15 doesn’t speak yet.
Bedrock also serves the same open models at a second, newer address, which
LM15 calls bedrock-mantle-chat. It uses shorter IDs, without the version at
the end, and it can list the models it serves. For most models, the two
addresses behave the same. Here’s one where they don’t. This is OpenAI’s open model,
gpt-oss-120b, through bedrock-chat:
from lm15 import LMRouter, Message, Request
router = LMRouter()request = Request( model="bedrock-chat:openai.gpt-oss-120b-1:0", system=( "You are the field assistant for a wildlife research " "station. Answer in two sentences." ), messages=[Message.user( "What might be eating the acorns under our oak trees at " "night?" )],)print(router.complete(request).text)<reasoning>We need to answer in two sentences. As a field assistant. Provide likely predators: squirrels, mice, chipmunks, raccoons, deer, birds like jays, etc. Mention nocturnal activity. Two sentences only.</reasoning>Common nighttime acorn pick‑pockets include gray squirrels and deer mice, as well as raccoons and striped skunks that forage after dark. You may also see nocturnal birds such as blue jays or even wintering woodpeckers scavenging the fallen nuts.
import { LMRouter, Message } from "@lm15/lm15";
const router = new LMRouter();const request = { model: "bedrock-chat:openai.gpt-oss-120b-1:0", system: "You are the field assistant for a wildlife research station. " + "Answer in two sentences.", messages: [Message.user( "What might be eating the acorns under our oak trees at night?", )],};const response = await router.complete(request);console.log(response.text);<reasoning>We need to answer in two sentences. As field assistant, suggest possible nocturnal acorn predators: squirrels, mice, chipmunks, deer (though not at night), raccoons, possums, insects like weevils, and maybe birds (nighthawks). Provide concise answer exactly two sentences.</reasoning>Likely candidates are nocturnal mammals such as eastern gray squirrels, mice, chipmunks, raccoons, or opossums, all of which forage on fallen acorns after dark. Insects like acorn weevils can also gnaw the nuts, but the rapid disappearance you’re seeing is most often caused by those small mammals visiting the ground at night.
use lm15::{LMRouter, Message, Request};
// Dependencies: lm15, tokio (macros, rt-multi-thread)#[tokio::main]async fn main() -> Result<(), Box<dyn std::error::Error>> { let router = LMRouter::new(); let request = Request { model: "bedrock-chat:openai.gpt-oss-120b-1:0".into(), system: Some(concat!( "You are the field assistant for a wildlife research ", "station. Answer in two sentences.", ).into()), messages: vec![Message::user(concat!( "What might be eating the acorns under our oak trees at ", "night?", ))?], ..Default::default() }; let response = router.complete(&request).await?; println!("{}", response.text().unwrap_or_default()); Ok(())}<reasoning>We need to answer in two sentences per instruction. Provide possible nocturnal acorn eaters: squirrels, rodents, raccoons, deer, birds like jays? At night, likely raccoons, opossums, mice, voles, chipmunks. Also insects? Provide concise answer.</reasoning>Likely candidates are nocturnal mammals such as raccoons, opossums, mice, voles, and chipmunks, all of which are active after dark and known to hoard or eat acorns. Larger nighttime foragers like deer may also nibble the fallen nuts, especially when food is scarce.
package main
import ( "context" "fmt" lm15 "github.com/lm15-dev/lm15-go/v2")
func main() { router := lm15.NewRouter() request := &lm15.Request{ Model: "bedrock-chat:openai.gpt-oss-120b-1:0", System: lm15.System( "You are the field assistant for a wildlife research " + "station. Answer in two sentences.", ), Messages: []lm15.Message{ lm15.UserMessage( "What might be eating the acorns under our oak trees " + "at night?", ), }, } response, err := router.Complete(context.Background(), request) if err != nil { panic(err) } fmt.Println(response.TextOr(""))}<reasoning>We need answer in two sentences. Provide possible predators: squirrels, deer, mice, raccoons, chipmunks, birds like jays, maybe squirrels. Mention nocturnal species like raccoons, opossums, deer may browse. Provide concise.</reasoning>Most likely nocturnal foragers such as raccoons, opossums, mice, and chipmunks are scooping up the fallen acorns under cover of darkness. Larger night‑active herbivores like deer can also browse them, especially when the supply is abundant.
This page has no R example yet: choose Python, TypeScript, Rust or Go above.
This page has no Julia example yet: choose Python, TypeScript, Rust or Go above.
The answer begins with the model’s reasoning, wrapped in <reasoning> tags,
inside the text. At this address, Bedrock returns gpt-oss’s reasoning as part
of the answer, and LM15 passes the text on as it came. Here’s the same
request through bedrock-mantle-chat, where the ID drops its -1:0:
from lm15 import LMRouter, Message, Request
router = LMRouter()request = Request( model="bedrock-mantle-chat:openai.gpt-oss-120b", system=( "You are the field assistant for a wildlife research " "station. Answer in two sentences." ), messages=[Message.user( "What might be eating the acorns under our oak trees at " "night?" )],)print(router.complete(request).text)Squirrels, mice, chipmunks, raccoons, and even deer are the most common nocturnal visitors that will crack open and eat fallen acorns. Smaller culprits like weevil larvae or ant colonies can also damage them, especially if the nuts are left on the ground for several days.
import { LMRouter, Message } from "@lm15/lm15";
const router = new LMRouter();const request = { model: "bedrock-mantle-chat:openai.gpt-oss-120b", system: "You are the field assistant for a wildlife research station. " + "Answer in two sentences.", messages: [Message.user( "What might be eating the acorns under our oak trees at night?", )],};const response = await router.complete(request);console.log(response.text);Likely culprits include nocturnal foragers such as eastern gray squirrels, deer mice, voles, and raccoons, as well as night‑active birds like blue jays and woodpeckers that stash and retrieve acorns after dark. In some regions, insects (e.g., weevils) and small mammals such as chipmunks may also harvest fallen acorns during the night hours.
use lm15::{LMRouter, Message, Request};
// Dependencies: lm15, tokio (macros, rt-multi-thread)#[tokio::main]async fn main() -> Result<(), Box<dyn std::error::Error>> { let router = LMRouter::new(); let request = Request { model: "bedrock-mantle-chat:openai.gpt-oss-120b".into(), system: Some(concat!( "You are the field assistant for a wildlife research ", "station. Answer in two sentences.", ).into()), messages: vec![Message::user(concat!( "What might be eating the acorns under our oak trees at ", "night?", ))?], ..Default::default() }; let response = router.complete(&request).await?; println!("{}", response.text().unwrap_or_default()); Ok(())}Likely culprits are nocturnal mammals such as raccoons, opossums, mice, and chipmunks, all of which forage under trees after dark. Some night‑active birds (e.g., jays or nuthatches) and even deer may also snatch acorns in the twilight hours.
package main
import ( "context" "fmt" lm15 "github.com/lm15-dev/lm15-go/v2")
func main() { router := lm15.NewRouter() request := &lm15.Request{ Model: "bedrock-mantle-chat:openai.gpt-oss-120b", System: lm15.System( "You are the field assistant for a wildlife research " + "station. Answer in two sentences.", ), Messages: []lm15.Message{ lm15.UserMessage( "What might be eating the acorns under our oak trees " + "at night?", ), }, } response, err := router.Complete(context.Background(), request) if err != nil { panic(err) } fmt.Println(response.TextOr(""))}Most likely nocturnal foragers such as gray/fox squirrels, mice, chipmunks, raccoons, or opossums are scavenging the fallen acorns after dark. In addition, larger herbivores like deer may sample the acorns at night, especially when daylight predators are less active.
This page has no R example yet: choose Python, TypeScript, Rust or Go above.
This page has no Julia example yet: choose Python, TypeScript, Rust or Go above.
This time the text is the answer alone. The newer address returns the
reasoning separately, and LM15 keeps it apart from the text, as it does for
reasoning models everywhere (see
Work with reasoning models). A good rule of thumb is to
use bedrock-chat for most models, and bedrock-mantle-chat for gpt-oss.
The newer address doesn’t exist in every region, though. In Canada Central, a
request to it failed to connect at all when we tried.
Claude on Bedrock
Section titled “Claude on Bedrock”Claude answers on a different API from the open models: Anthropic’s own, which
Bedrock offers for Claude Opus 4.7 and later. LM15 reaches it through the
provider bedrock-anthropic, with IDs such as anthropic.claude-opus-4-7.
Older Claude models answer only on Bedrock’s native API, and LM15 can’t reach
them yet.
We couldn’t record an answer, because AWS hasn’t opened Claude to our test account. Here’s what that looks like:
from lm15 import AuthError, LMRouter, Message, Request
router = LMRouter()request = Request( model="bedrock-anthropic:anthropic.claude-opus-4-7", system=( "You are the field assistant for a wildlife research " "station. Answer in two sentences." ), messages=[Message.user( "What might be eating the acorns under our oak trees at " "night?" )],)try: print(router.complete(request).text)except AuthError as error: print(error)anthropic.claude-opus-4-7 is not available for this account. You can explore other available models on Amazon Bedrock. For additional access options, contact AWS Sales at https://aws.amazon.com/contact-us/sales-support/ (bedrock-anthropic, HTTP 403, request req_ctnt7d62b4eqeev6ezvk6i7ugnsswksfrq2236j3wr3c2u7t7hqq)
credential came from: ~/.aws/credentials
To fix:
- Check that your API key is correct and not expired
- Pass the key explicitly (api_key, or RouterConfig api_keys), or on a host with an environment set AWS_BEARER_TOKEN_BEDROCK=...
- Verify your bedrock-anthropic account/project has accessimport { LMRouter, Message } from "@lm15/lm15";
const router = new LMRouter();const request = { model: "bedrock-anthropic:anthropic.claude-opus-4-7", system: "You are the field assistant for a wildlife research station. " + "Answer in two sentences.", messages: [Message.user( "What might be eating the acorns under our oak trees at night?", )],};try { console.log((await router.complete(request)).text);} catch (error) { console.log(String(error));}AuthError: anthropic.claude-opus-4-7 is not available for this account. You can explore other available models on Amazon Bedrock. For additional access options, contact AWS Sales at https://aws.amazon.com/contact-us/sales-support/
Credential came from: ~/.aws/credentials [shared-credentials-file] (bedrock-anthropic, HTTP 403, request req_edzj6kv37w7enl4dvfovkbo7rumyyljeseyrtndsxb2bvml3jdnq)
To fix:
- Check that your API key is correct and not expired
- Pass the key explicitly (apiKey, or RouterConfig apiKeys), or on a host with an environment set AWS_BEARER_TOKEN_BEDROCK=...
- Verify your bedrock-anthropic account/project has accessuse lm15::{LMRouter, Message, Request};
// Dependencies: lm15, tokio (macros, rt-multi-thread)#[tokio::main]async fn main() -> Result<(), Box<dyn std::error::Error>> { let router = LMRouter::new(); let request = Request { model: "bedrock-anthropic:anthropic.claude-opus-4-7".into(), system: Some(concat!( "You are the field assistant for a wildlife research ", "station. Answer in two sentences.", ).into()), messages: vec![Message::user(concat!( "What might be eating the acorns under our oak trees at ", "night?", ))?], ..Default::default() }; match router.complete(&request).await { Ok(response) => { println!("{}", response.text().unwrap_or_default()) } Err(error) => println!("{error}"), } Ok(())}AuthError: anthropic.claude-opus-4-7 is not available for this account. You can explore other available models on Amazon Bedrock. For additional access options, contact AWS Sales at https://aws.amazon.com/contact-us/sales-support/ (bedrock-anthropic, HTTP 403, request req_cdaggiqse47rx7g5orfwn26uegnis3gfg2xjnwa2oxnyb4tx5xha) Credential came from: ~/.aws/credentials (shared-credentials-file)
package main
import ( "context" "fmt" lm15 "github.com/lm15-dev/lm15-go/v2")
func main() { router := lm15.NewRouter() request := &lm15.Request{ Model: "bedrock-anthropic:anthropic.claude-opus-4-7", System: lm15.System( "You are the field assistant for a wildlife research " + "station. Answer in two sentences.", ), Messages: []lm15.Message{ lm15.UserMessage( "What might be eating the acorns under our oak trees " + "at night?", ), }, } response, err := router.Complete(context.Background(), request) if err != nil { fmt.Println(err) return } fmt.Println(response.TextOr(""))}anthropic.claude-opus-4-7 is not available for this account. You can explore other available models on Amazon Bedrock. For additional access options, contact AWS Sales at https://aws.amazon.com/contact-us/sales-support/ (bedrock-anthropic, HTTP 403, request req_xsq4jgtkrlogfexvj7x5nstxa5apnooo56peud3bwg2mmjjwo2kq)
credential came from: ~/.aws/credentials
To fix:
- Check that your API key is correct and not expired
- Pass the key explicitly (api_key, or RouterConfig api_keys), or on a host with an environment set AWS_BEARER_TOKEN_BEDROCK=...
- Verify your bedrock-anthropic account/project has accessThis page has no R example yet: choose Python, TypeScript, Rust or Go above.
This page has no Julia example yet: choose Python, TypeScript, Rust or Go above.
The first sentence is AWS’s own message, and it’s the one to read. The account isn’t allowed to use this model. The status, 403, says the same thing in fewer words. LM15 signed the request correctly, and the error goes on to say which credential it used. In Python, TypeScript and Go, it then lists LM15’s general advice for a refused sign-in; only the last point, about the account’s access, applies here. The fix is on the AWS side, in the Bedrock console, or through AWS support as the message says.
There’s one more way to use Claude through AWS: Claude Platform on AWS,
which Anthropic runs and AWS bills. LM15 reaches it through the provider
aws-anthropic, which also needs the ANTHROPIC_AWS_WORKSPACE_ID variable.
We haven’t tested it against the real service yet.
Run on AWS
Section titled “Run on AWS”On EC2, ECS, EKS or Lambda, your program runs as an IAM role, an identity AWS gives to programs instead of people. Give the role the two Bedrock permissions from the setup, attach it, and store no key on the machine. LM15 asks the machine for the role’s temporary credentials, and asks again before they expire.
The code from your laptop works there unchanged, once the machine knows its region (more on that below). It’s better, though, to say which sign-in you expect:
from lm15 import LMRouter, Message, Request, RouterConfig
router = LMRouter(RouterConfig( credentials={"bedrock-chat": "platform"},))request = Request( model="bedrock-chat:deepseek.v3.2", system=( "You are the field assistant for a wildlife research " "station. Answer in two sentences." ), messages=[Message.user( "What might be eating the acorns under our oak trees at " "night?" )],)print(router.complete(request).text)Several animals could be responsible. Common nighttime acorn predators include squirrels (which are active day and night), raccoons, opossums, deer, and mice or voles. To confirm, you might look for tracks, scat, or set up a wildlife camera.
import { LMRouter, Message } from "@lm15/lm15";
const router = new LMRouter({ credentials: { "bedrock-chat": "platform" },});const request = { model: "bedrock-chat:deepseek.v3.2", system: "You are the field assistant for a wildlife research station. " + "Answer in two sentences.", messages: [Message.user( "What might be eating the acorns under our oak trees at night?", )],};const response = await router.complete(request);console.log(response.text);Common nighttime acorn predators include small mammals such as squirrels, raccoons, opossums, and deer mice. It would be helpful to set up a motion-activated camera to confirm which species is visiting your trees.
use lm15::{LMRouter, Message, Request, RouterConfig};
// Dependencies: lm15, tokio (macros, rt-multi-thread)#[tokio::main]async fn main() -> Result<(), Box<dyn std::error::Error>> { let config = RouterConfig::new().credential("bedrock-chat", "platform"); let router = LMRouter::with_config(config)?; let request = Request { model: "bedrock-chat:deepseek.v3.2".into(), system: Some(concat!( "You are the field assistant for a wildlife research ", "station. Answer in two sentences.", ).into()), messages: vec![Message::user(concat!( "What might be eating the acorns under our oak trees at ", "night?", ))?], ..Default::default() }; let response = router.complete(&request).await?; println!("{}", response.text().unwrap_or_default()); Ok(())}Several nocturnal animals could be responsible. Likely candidates include deer, raccoons, squirrels (which are active both day and night), wild turkeys, and even nocturnal rodents like mice or voles. You could set up a motion-activated camera to identify the specific animals visiting your oak trees.
package main
import ( "context" "fmt" lm15 "github.com/lm15-dev/lm15-go/v2")
func main() { router, err := lm15.NewRouterWithConfig(lm15.RouterConfig{ Credentials: map[string]string{"bedrock-chat": "platform"}, }) if err != nil { panic(err) } request := &lm15.Request{ Model: "bedrock-chat:deepseek.v3.2", System: lm15.System( "You are the field assistant for a wildlife research " + "station. Answer in two sentences.", ), Messages: []lm15.Message{ lm15.UserMessage( "What might be eating the acorns under our oak trees " + "at night?", ), }, } response, err := router.Complete(context.Background(), request) if err != nil { panic(err) } fmt.Println(response.TextOr(""))}Several nocturnal animals are likely candidates for eating acorns under your oak trees. Common culprits include raccoons, opossums, deer, and mice or voles, all of which forage at night and consume acorns as a food source. To identify the specific animal, you could look for tracks, scat, or check for disturbed ground around the trees after dark.
This page has no R example yet: choose Python, TypeScript, Rust or Go above.
This page has no Julia example yet: choose Python, TypeScript, Rust or Go above.
"platform" tells LM15 to use the machine’s own role and nothing else.
Without it, LM15 walks the whole list from the doctor’s report, so a program
deployed with someone’s leftover AWS_ACCESS_KEY_ID would quietly run as that
key. With it, a missing role stops the program at the first request, with an
error that names what LM15 looked for. We ran this on an EC2 instance whose
only identity was a role with the two Bedrock permissions, and AWS_REGION
set to us-east-1; it answered in all four languages. On a laptop, the same
program stops at once, which is what you want: a laptop isn’t the machine it
names.
We ran it once more on the same instance without AWS_REGION:
NotConfiguredError: bedrock-chat: setting 'region' is required and has no default; set AWS_REGION or AWS_DEFAULT_REGION
To fix:
- set AWS_REGION or AWS_DEFAULT_REGIONNotConfiguredError: bedrock-chat: setting 'region' is required and has no default; set AWS_REGION or AWS_DEFAULT_REGION
To fix:
- set AWS_REGION or AWS_DEFAULT_REGIONError: NotConfiguredError(ErrorMeta { message: "bedrock-chat: setting \"region\" is required and has no default; set AWS_REGION or AWS_DEFAULT_REGION", provider: Some("bedrock-chat"), provider_code: None, status: None, request_id: None, retry_after: None, rate_limit_headers: DiagnosticHeaders({}), content_type: None, body_excerpt: None, credential_source: None, feature: None })panic: bedrock-chat: setting "region" is required and has no default; set AWS_REGION or AWS_DEFAULT_REGION To fix: - set AWS_REGION or AWS_DEFAULT_REGION
This page has no R example yet: choose Python, TypeScript, Rust or Go above.
This page has no Julia example yet: choose Python, TypeScript, Rust or Go above.
The role is there, but nothing says where to send the request. EC2 doesn’t set
AWS_REGION for you, so set it in the instance’s environment, or put the
region in the router’s settings. (Lambda sets AWS_REGION on its own.)
Run somewhere else
Section titled “Run somewhere else”GitHub Actions, another cloud, or a server in your own building have no role
to ask for. Two names cover them. On EKS with IAM roles for service accounts,
and anywhere else that hands your program a web-identity token, name the
sign-in "workload": LM15 trades the token for the role’s credentials. When
the credentials arrive as environment variables, as they do from AWS’s
GitHub Action, name it "environment": LM15 reads AWS_ACCESS_KEY_ID,
AWS_SECRET_ACCESS_KEY and, for temporary credentials,
AWS_SESSION_TOKEN. LM15’s shared tests cover both; we didn’t record them
for this page.
Use a Bedrock API key
Section titled “Use a Bedrock API key”Some tools only know how to send a key, and Bedrock has keys too. Short-term keys last at most 12 hours and act for the identity that made them. Long-term keys last much longer, and AWS recommends them only for trying things out. Create one in the Bedrock console, under API keys, and put it in the environment:
export AWS_BEARER_TOKEN_BEDROCK=bedrock-api-key-...LM15 checks this variable right after any key your program gives the router, before everything else in the doctor’s list, so the first program on this page works with it unchanged, as long as there’s a region. We ran that program with a short-term key and a region and nothing else, and it answered in all four languages. A program that runs for longer than a working day is better off with a role, because a key that expires overnight will stop it.
Mistakes that cost the most time
Section titled “Mistakes that cost the most time”- “The provided model identifier is invalid.” Check the region first
(the doctor’s
setting regionline), then the ID’s form:bedrock-chattakes IDs with a version, such asopenai.gpt-oss-120b-1:0, andbedrock-mantle-chattakes them without, such asopenai.gpt-oss-120b. - Reasoning in the answer. gpt-oss through
bedrock-chatputs its reasoning in the text. Usebedrock-mantle-chatfor it. - “Not available for this account.” The model is closed to your account, and no change to your code will open it. See Claude on Bedrock.
- No region on EC2. A role is not a region. Set
AWS_REGION. - The wrong account. A leftover
AWS_ACCESS_KEY_IDorAWS_BEARER_TOKEN_BEDROCKcomes before your profile. The doctor shows which one wins.
Try it yourself
Section titled “Try it yourself”Predict the answer before you run the doctor.
- Your profile’s region is
eu-west-1, and you runexport AWS_REGION=us-east-1. Which region does a request use? - A program sets the region
us-east-1in its router’s settings, and runs on an EC2 instance whereAWS_REGION=eu-west-1. Which region does it use? - On the same instance, someone adds
AWS_ACCESS_KEY_IDandAWS_SECRET_ACCESS_KEYfor a different account to the environment. Which account pays, with and without"platform"?
What to expect
us-east-1. The environment variable comes before the profile, and the doctor saysfrom env $AWS_REGION.us-east-1. The router’s settings come first, as in Choose a region.- Without
"platform", the other account: environment variables come before the instance’s role in the list. With it, the instance’s role, because LM15 looks nowhere else. This is the leftover-key problem from Run on AWS.
Use a cloud provider compares Bedrock with Azure and Google Cloud, and lists the providers LM15 has for each. Handle errors and retries shows how to catch a refused request in a long-running program. Set up authentication explains the rule behind this page: LM15 always says which credential it used.