Bug: AWS Bedrock fails in Asia Pacific regions with invalid model identifier error #8900

Open
opened 2026-02-16 18:11:07 -05:00 by yindo · 2 comments
Owner

Originally created by @datanerdie on GitHub (Feb 9, 2026).

Originally assigned to: @rekram1-node on GitHub.

Bug: AWS Bedrock fails in Asia Pacific regions with "invalid model identifier" error

Description

When using OpenCode with AWS Bedrock in Asia Pacific regions (e.g., ap-southeast-2), OpenCode attempts to use EU inference profile models (eu.anthropic.claude-haiku-4-5-20251001-v1:0) which don't exist in these regions, causing "The provided model identifier is invalid" errors.

Environment

  • OpenCode Version: Latest (main branch)
  • Region: ap-southeast-2 (Sydney, Australia)
  • AWS Profile: Configured with valid credentials
  • Provider: amazon-bedrock
  • Configuration:
    {
      "provider": {
        "amazon-bedrock": {
          "options": {
            "region": "ap-southeast-2",
            "profile": "bedrock-user"
          }
        }
      }
    }
    

Steps to Reproduce

  1. Configure AWS Bedrock provider with ap-southeast-2 region
  2. Configure oh-my-opencode agents to use Bedrock models:
    {
      "agents": {
        "build": {
          "model": "amazon-bedrock/anthropic.claude-sonnet-4-5-20250929-v1:0"
        }
      }
    }
    
  3. Run any OpenCode command that triggers the title generation agent
  4. Observe error logs showing EU model being used

Expected Behavior

OpenCode should:

  1. Detect the ap-southeast-2 region
  2. Select appropriate models for that region:
    • Direct models: anthropic.claude-haiku-4-5-20251001-v1:0
    • Global profiles: global.anthropic.claude-haiku-4-5-20251001-v1:0
    • AU profiles: au.anthropic.claude-haiku-4-5-20251001-v1:0 (for Australia)

Actual Behavior

OpenCode incorrectly selects EU inference profile models:

ERROR service=llm providerID=amazon-bedrock modelID=eu.anthropic.claude-haiku-4-5-20251001-v1:0
error={"error":{"statusCode":400,"responseBody":"{\"message\":\"The provided model identifier is invalid.\"}"}}

The API correctly calls the ap-southeast-2 endpoint but with an invalid EU model ID:

https://bedrock-runtime.ap-southeast-2.amazonaws.com/model/eu.anthropic.claude-haiku-4-5-20251001-v1%3A0/converse-stream

Root Cause

The bug is in the getSmallModel() function in /packages/opencode/src/provider/provider.ts (lines 1174-1195).

Problem 1: Incomplete Prefix List (Line 1175)

const crossRegionPrefixes = ["global.", "us.", "eu."]  // ❌ Missing "au.", "apac.", "jp."

This doesn't match the complete list used in getModel() at line 243:

const crossRegionPrefixes = ["global.", "us.", "eu.", "jp.", "apac.", "au."]  // ✅

Problem 2: Region Check Only for US/EU (Line 1188)

if (regionPrefix === "us" || regionPrefix === "eu") {  // ❌ Ignores all other regions!
  const regionalMatch = candidates.find((m) => m.startsWith(`${regionPrefix}.`))
  if (regionalMatch) return getModel(providerID, regionalMatch)
}

For ap-southeast-2:

  • regionPrefix = "ap" (from region.split("-")[0])
  • Condition evaluates to false
  • Regional model selection is completely skipped

Proposed Fix

Option 1: Add AP Region Support (Recommended)

if (providerID === "amazon-bedrock") {
  const crossRegionPrefixes = ["global.", "us.", "eu.", "jp.", "apac.", "au."]  // Add missing prefixes
  const candidates = Object.keys(provider.models).filter((m) => m.includes(item))

  // 1. Try global prefix (works everywhere)
  const globalMatch = candidates.find((m) => m.startsWith("global."))
  if (globalMatch) return getModel(providerID, globalMatch)

  // 2. Try regional prefix
  const region = provider.options?.region
  if (region) {
    let regionPrefix = region.split("-")[0]

    // Map region prefixes to inference profile prefixes
    if (regionPrefix === "ap") {
      if (["ap-southeast-2", "ap-southeast-4"].includes(region)) {
        regionPrefix = "au"  // Australia regions
      } else if (region === "ap-northeast-1") {
        regionPrefix = "jp"  // Tokyo region
      } else {
        regionPrefix = "apac"  // Other APAC regions
      }
    }

    if (["us", "eu", "au", "jp", "apac"].includes(regionPrefix)) {
      const regionalMatch = candidates.find((m) => m.startsWith(`${regionPrefix}.`))
      if (regionalMatch) return getModel(providerID, regionalMatch)
    }
  }

  // 3. Try unprefixed model
  const unprefixed = candidates.find((m) => !crossRegionPrefixes.some((p) => m.startsWith(p)))
  if (unprefixed) return getModel(providerID, unprefixed)
}

Option 2: Fallback to Global for Unsupported Regions (Simpler)

if (regionPrefix === "us" || regionPrefix === "eu") {
  const regionalMatch = candidates.find((m) => m.startsWith(`${regionPrefix}.`))
  if (regionalMatch) return getModel(providerID, regionalMatch)
} else {
  // For other regions, prefer global profiles
  const globalMatch = candidates.find((m) => m.startsWith("global."))
  if (globalMatch) return getModel(providerID, globalMatch)
}

Additional Context

  • The main getModel() function (lines 240-320) correctly handles AP regions with proper au., jp., and apac. prefix mapping
  • The inconsistency is only in getSmallModel() used for background tasks like title generation
  • All AWS Bedrock tests in /test/provider/amazon-bedrock.test.ts use only us-east-1 and eu-west-1 regions, which is why this bug wasn't caught

Impact

  • Affected regions: All Asia Pacific regions (ap-*), Japan (ap-northeast-1), and potentially other non-US/EU regions
  • Affected users: Anyone using AWS Bedrock outside US/EU regions
  • Workaround: Remove oh-my-opencode plugin (OpenCode falls back to Anthropic API)

Test Coverage Suggestion

Add test cases for AP regions in amazon-bedrock.test.ts:

test("Bedrock: getSmallModel works in ap-southeast-2 region", async () => {
  await using tmp = await tmpdir({
    init: async (dir) => {
      await Bun.write(
        path.join(dir, "opencode.json"),
        JSON.stringify({
          $schema: "https://opencode.ai/config.json",
          provider: {
            "amazon-bedrock": {
              options: {
                region: "ap-southeast-2",
              },
            },
          },
        }),
      )
    },
  })
  await Instance.provide({
    directory: tmp.path,
    init: async () => {
      Env.set("AWS_PROFILE", "default")
    },
    fn: async () => {
      const smallModel = await Provider.getSmallModel("amazon-bedrock")
      expect(smallModel).toBeDefined()
      // Should use global. or au. prefix, NOT eu.
      expect(smallModel?.id).toMatch(/^(global\.|au\.|anthropic\.)/)
      expect(smallModel?.id).not.toMatch(/^eu\./)
    },
  })
})

Related Code

  • Bug location: /packages/opencode/src/provider/provider.ts:1147-1211 (getSmallModel())
  • Working reference: /packages/opencode/src/provider/provider.ts:240-320 (getModel() - correctly handles AP regions)
  • Tests: /packages/opencode/test/provider/amazon-bedrock.test.ts (missing AP region test coverage)
Originally created by @datanerdie on GitHub (Feb 9, 2026). Originally assigned to: @rekram1-node on GitHub. # Bug: AWS Bedrock fails in Asia Pacific regions with "invalid model identifier" error ## Description When using OpenCode with AWS Bedrock in Asia Pacific regions (e.g., `ap-southeast-2`), OpenCode attempts to use EU inference profile models (`eu.anthropic.claude-haiku-4-5-20251001-v1:0`) which don't exist in these regions, causing "The provided model identifier is invalid" errors. ## Environment - **OpenCode Version:** Latest (main branch) - **Region:** `ap-southeast-2` (Sydney, Australia) - **AWS Profile:** Configured with valid credentials - **Provider:** `amazon-bedrock` - **Configuration:** ```json { "provider": { "amazon-bedrock": { "options": { "region": "ap-southeast-2", "profile": "bedrock-user" } } } } ``` ## Steps to Reproduce 1. Configure AWS Bedrock provider with `ap-southeast-2` region 2. Configure oh-my-opencode agents to use Bedrock models: ```json { "agents": { "build": { "model": "amazon-bedrock/anthropic.claude-sonnet-4-5-20250929-v1:0" } } } ``` 3. Run any OpenCode command that triggers the title generation agent 4. Observe error logs showing EU model being used ## Expected Behavior OpenCode should: 1. Detect the `ap-southeast-2` region 2. Select appropriate models for that region: - Direct models: `anthropic.claude-haiku-4-5-20251001-v1:0` - Global profiles: `global.anthropic.claude-haiku-4-5-20251001-v1:0` - AU profiles: `au.anthropic.claude-haiku-4-5-20251001-v1:0` (for Australia) ## Actual Behavior OpenCode incorrectly selects EU inference profile models: ``` ERROR service=llm providerID=amazon-bedrock modelID=eu.anthropic.claude-haiku-4-5-20251001-v1:0 error={"error":{"statusCode":400,"responseBody":"{\"message\":\"The provided model identifier is invalid.\"}"}} ``` The API correctly calls the ap-southeast-2 endpoint but with an invalid EU model ID: ``` https://bedrock-runtime.ap-southeast-2.amazonaws.com/model/eu.anthropic.claude-haiku-4-5-20251001-v1%3A0/converse-stream ``` ## Root Cause The bug is in the `getSmallModel()` function in `/packages/opencode/src/provider/provider.ts` (lines 1174-1195). ### Problem 1: Incomplete Prefix List (Line 1175) ```typescript const crossRegionPrefixes = ["global.", "us.", "eu."] // ❌ Missing "au.", "apac.", "jp." ``` This doesn't match the complete list used in `getModel()` at line 243: ```typescript const crossRegionPrefixes = ["global.", "us.", "eu.", "jp.", "apac.", "au."] // ✅ ``` ### Problem 2: Region Check Only for US/EU (Line 1188) ```typescript if (regionPrefix === "us" || regionPrefix === "eu") { // ❌ Ignores all other regions! const regionalMatch = candidates.find((m) => m.startsWith(`${regionPrefix}.`)) if (regionalMatch) return getModel(providerID, regionalMatch) } ``` For `ap-southeast-2`: - `regionPrefix` = `"ap"` (from `region.split("-")[0]`) - Condition evaluates to `false` - Regional model selection is completely skipped ## Proposed Fix ### Option 1: Add AP Region Support (Recommended) ```typescript if (providerID === "amazon-bedrock") { const crossRegionPrefixes = ["global.", "us.", "eu.", "jp.", "apac.", "au."] // Add missing prefixes const candidates = Object.keys(provider.models).filter((m) => m.includes(item)) // 1. Try global prefix (works everywhere) const globalMatch = candidates.find((m) => m.startsWith("global.")) if (globalMatch) return getModel(providerID, globalMatch) // 2. Try regional prefix const region = provider.options?.region if (region) { let regionPrefix = region.split("-")[0] // Map region prefixes to inference profile prefixes if (regionPrefix === "ap") { if (["ap-southeast-2", "ap-southeast-4"].includes(region)) { regionPrefix = "au" // Australia regions } else if (region === "ap-northeast-1") { regionPrefix = "jp" // Tokyo region } else { regionPrefix = "apac" // Other APAC regions } } if (["us", "eu", "au", "jp", "apac"].includes(regionPrefix)) { const regionalMatch = candidates.find((m) => m.startsWith(`${regionPrefix}.`)) if (regionalMatch) return getModel(providerID, regionalMatch) } } // 3. Try unprefixed model const unprefixed = candidates.find((m) => !crossRegionPrefixes.some((p) => m.startsWith(p))) if (unprefixed) return getModel(providerID, unprefixed) } ``` ### Option 2: Fallback to Global for Unsupported Regions (Simpler) ```typescript if (regionPrefix === "us" || regionPrefix === "eu") { const regionalMatch = candidates.find((m) => m.startsWith(`${regionPrefix}.`)) if (regionalMatch) return getModel(providerID, regionalMatch) } else { // For other regions, prefer global profiles const globalMatch = candidates.find((m) => m.startsWith("global.")) if (globalMatch) return getModel(providerID, globalMatch) } ``` ## Additional Context - The main `getModel()` function (lines 240-320) correctly handles AP regions with proper `au.`, `jp.`, and `apac.` prefix mapping - The inconsistency is only in `getSmallModel()` used for background tasks like title generation - All AWS Bedrock tests in `/test/provider/amazon-bedrock.test.ts` use only `us-east-1` and `eu-west-1` regions, which is why this bug wasn't caught ## Impact - **Affected regions:** All Asia Pacific regions (`ap-*`), Japan (`ap-northeast-1`), and potentially other non-US/EU regions - **Affected users:** Anyone using AWS Bedrock outside US/EU regions - **Workaround:** Remove oh-my-opencode plugin (OpenCode falls back to Anthropic API) ## Test Coverage Suggestion Add test cases for AP regions in `amazon-bedrock.test.ts`: ```typescript test("Bedrock: getSmallModel works in ap-southeast-2 region", async () => { await using tmp = await tmpdir({ init: async (dir) => { await Bun.write( path.join(dir, "opencode.json"), JSON.stringify({ $schema: "https://opencode.ai/config.json", provider: { "amazon-bedrock": { options: { region: "ap-southeast-2", }, }, }, }), ) }, }) await Instance.provide({ directory: tmp.path, init: async () => { Env.set("AWS_PROFILE", "default") }, fn: async () => { const smallModel = await Provider.getSmallModel("amazon-bedrock") expect(smallModel).toBeDefined() // Should use global. or au. prefix, NOT eu. expect(smallModel?.id).toMatch(/^(global\.|au\.|anthropic\.)/) expect(smallModel?.id).not.toMatch(/^eu\./) }, }) }) ``` ## Related Code - **Bug location:** `/packages/opencode/src/provider/provider.ts:1147-1211` (`getSmallModel()`) - **Working reference:** `/packages/opencode/src/provider/provider.ts:240-320` (`getModel()` - correctly handles AP regions) - **Tests:** `/packages/opencode/test/provider/amazon-bedrock.test.ts` (missing AP region test coverage)
Author
Owner

@github-actions[bot] commented on GitHub (Feb 9, 2026):

This issue might be a duplicate of existing issues. Please check:

  • #12280: Session title generation fails for non-EU Amazon Bedrock regions - same root cause in getSmallModel()
  • #467: AWS Bedrock not working on regions outside us-east-1 - regional model selection issue
  • #5812: [BUG] Bedrock provider: config options.region ignored for model ID prefixing - region handling in getModel()
  • #12052: Bedrock US Opus identified is invalid - invalid model identifier error
  • #4784: Opus 4.5 in AWS Bedrock "undefined: The provided model identifier is invalid." - same error
  • #11037: undefined: The provided model identifier is invalid - similar issue with AWS Bedrock

Feel free to ignore if none of these address your specific case.

@github-actions[bot] commented on GitHub (Feb 9, 2026): This issue might be a duplicate of existing issues. Please check: - #12280: Session title generation fails for non-EU Amazon Bedrock regions - same root cause in getSmallModel() - #467: AWS Bedrock not working on regions outside us-east-1 - regional model selection issue - #5812: [BUG] Bedrock provider: config options.region ignored for model ID prefixing - region handling in getModel() - #12052: Bedrock US Opus identified is invalid - invalid model identifier error - #4784: Opus 4.5 in AWS Bedrock "undefined: The provided model identifier is invalid." - same error - #11037: undefined: The provided model identifier is invalid - similar issue with AWS Bedrock Feel free to ignore if none of these address your specific case.
Author
Owner

@datanerdie commented on GitHub (Feb 9, 2026):

This issue identifies a remaining bug in PR #12281 which only partially fixed the regional model selection.

PR #12281 closed #12280 but only addressed US/EU regions. The fix is incomplete because:

  1. Line 1175: crossRegionPrefixes = ["global.", "us.", "eu."] - missing "au.", "apac.", "jp."
  2. Line 1188: if (regionPrefix === "us" || regionPrefix === "eu") - excludes all AP regions

The fix in PR #12281 should have matched the complete logic from getModel() at line 243 which correctly handles all regions including:

  • au. prefix for Australia (ap-southeast-2, ap-southeast-4)
  • jp. prefix for Japan (ap-northeast-1)
  • apac. prefix for other Asia Pacific regions

Affected regions still broken: ap-southeast-2, ap-southeast-4, ap-northeast-1, and other Asia Pacific regions.

Reference: The getModel() function at lines 291-318 shows the correct implementation for handling AP regions.

@datanerdie commented on GitHub (Feb 9, 2026): This issue identifies a **remaining bug** in PR #12281 which only partially fixed the regional model selection. PR #12281 closed #12280 but only addressed US/EU regions. The fix is incomplete because: 1. Line 1175: `crossRegionPrefixes = ["global.", "us.", "eu."]` - missing "au.", "apac.", "jp." 2. Line 1188: `if (regionPrefix === "us" || regionPrefix === "eu")` - excludes all AP regions The fix in PR #12281 should have matched the complete logic from `getModel()` at line 243 which correctly handles all regions including: - `au.` prefix for Australia (ap-southeast-2, ap-southeast-4) - `jp.` prefix for Japan (ap-northeast-1) - `apac.` prefix for other Asia Pacific regions **Affected regions still broken:** ap-southeast-2, ap-southeast-4, ap-northeast-1, and other Asia Pacific regions. **Reference:** The `getModel()` function at lines 291-318 shows the correct implementation for handling AP regions.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: anomalyco/opencode#8900