Your sandbox lease ended, or your team got a new sandbox account, and your app stopped working. Nothing is wrong with your code. This guide gets the same app running again in the new account.
When a lease ends, the sandbox account is wiped clean and returned to the pool. A new lease gives you an AWS account that is almost always a different one (a new Account ID), with nothing in it.
| Item | After expiry | What to do |
|---|---|---|
| Your code and workflow files on GitHub | β Kept | Nothing |
| Your API key value, if your app uses one (the string you chose in Step 6) | β Kept (it's just a string) | Reuse the same value |
| Your GitHub secrets | β οΈ Kept, but the AWS keys inside no longer work | Kiro does not need them. Replace them only for the optional GitHub Actions deploy |
| AWS Account ID | π New with a new lease | Step 1 |
| Lambda, API Gateway, S3 buckets, CloudFormation stack | β Deleted | Redeploy (Step 3) |
IAM user github-deployer and its access keys | β Deleted | Only needed for the optional GitHub Actions deploy |
| DynamoDB tables, uploaded files, CloudWatch logs | β Deleted for good | Re-create and re-seed (Step 5) |
| CloudFront, certificate, WAF, custom domain | β Deleted | Optional (Step 5) |
| Your API URL and website URL | π New after redeploy | Step 4 |
infra/template.yaml, backend/, frontend/ and .github/workflows/deploy.ymlAPI_KEY_VALUE in Step 6 of the main tutorial), you have that value, or you are happy to make up a new 20+ character stringap-southeast-5). Apps built earlier may still say ap-southeast-1 inside deploy.yml (see the note in Step 3)ETA-Sandbox-NN β Management console.| Region | Code |
|---|---|
| Malaysia (recommended, used in this tutorial) | ap-southeast-5 |
| Singapore | ap-southeast-1 |
| Jakarta | ap-southeast-3 |
| N. Virginia | us-east-1 |
| Oregon | us-west-2 |
sandbox profile uses that number.hi, and click Run. You should get an answer.In current sandbox accounts the Anthropic models work without a separate Model access request. If Bedrock shows a form asking about your use case, fill it in (for example "Student hackathon project") and wait for approval, which is usually instant.
Checked in a sandbox account, region Malaysia, in October 2026. Use these exact IDs in your Lambda code.
| Model | ID to use in code | Notes |
|---|---|---|
| Claude Haiku 4.5 (recommended) | global.anthropic.claude-haiku-4-5-20251001-v1:0 | Fast and cheap. Works in Malaysia and the other four regions. A brand-new account needs the one-time Anthropic form first. |
| Claude Haiku 5.5 | global.anthropic.claude-haiku-5-5 | Newer, but AWS enables it per account: it may answer "not available for this account" |
| Claude Sonnet 5.5 | global.anthropic.claude-sonnet-5-5 | More capable, costs more per request |
| Claude Sonnet 5 | global.anthropic.claude-sonnet-5 | Previous Sonnet generation |
| Claude Sonnet 4.6 / 4.5 | global.anthropic.claude-sonnet-4-6global.anthropic.claude-sonnet-4-5-20250929-v1:0 | Older Sonnet versions |
| Amazon Nova 2 Lite | global.amazon.nova-2-lite-v1:0 | Low-cost alternative |
| Claude 3 Haiku, Llama 3, image-generation models | β | Not offered in Malaysia |
| Claude Opus (any version) | β | β Blocked in sandbox accounts |
global. version of the ID. The plain ID anthropic.claude-haiku-4-5-20251001-v1:0 fails with "on-demand throughput isnβt supported". If your old code used the plain ID, change it in your Lambda file and in template.yaml before you redeploy.us-west-2 (Oregon, also allowed in the sandbox) and test it in the Playground first.If your Lambda gets an AccessDenied that does not mention a service control policy, your function's role is missing Bedrock permissions. Make sure its policy in template.yaml includes:
- Effect: Allow
Action:
- bedrock:InvokeModel
- bedrock:InvokeModelWithResponseStream
Resource:
- !Sub arn:aws:bedrock:${AWS::Region}:${AWS::AccountId}:inference-profile/global.*
- !Sub arn:aws:bedrock:${AWS::Region}::foundation-model/*
- arn:aws:bedrock:::foundation-model/*
You do not run any command yourself. Copy one prompt into Kiro and Kiro does the whole job on your computer: installs the tools that are missing (AWS CLI, SAM CLI, uv), sets up your sandbox sign-in, fixes the region and models, deploys, uploads the website and tests it. The only thing you do by hand is click Allow when the browser sign-in page opens, and answer if Kiro asks for your new Account ID.
You are my deployment assistant. My AWS sandbox expired and I got a NEW sandbox account. Redeploy this project there. You do EVERYTHING yourself: install missing tools, set up my sign-in, run every command, read the output, fix problems, and report. I only click "Allow" in the browser when the sign-in page opens. Never ask me to run commands.
RULES (follow strictly)
- Only touch the account that the AWS profile "sandbox" points to. Use --profile sandbox --region ap-southeast-5 (Malaysia) on every aws and sam command.
- Never create IAM users or access keys, never print or ask for secrets, never delete anything outside this project's own stack, never run git push, never overwrite an existing AWS profile or config file without making a backup copy first.
- Before each step, say in one line what you are about to do. If something fails, read the error, find the root cause (CloudFormation events, Lambda logs), fix it and retry. Stop and ask me only if you need a decision, my Account ID, or my sign-in.
STEPS
0. SET UP TOOLS. Detect my operating system. Check aws --version (need AWS CLI v2), sam --version (AWS SAM CLI) and uv --version. Install whatever is missing with the official method for my OS (macOS: Homebrew or the official installer; Windows: winget or the official MSI; Linux: the official installer). Ask me before anything that needs administrator or sudo rights. Show the final versions.
1. SET UP MY SIGN-IN. FIRST ask me for my NEW sandbox Account ID (12 digits, from my Active lease in the Innovation Sandbox web app) if I did not write it above, and remember it. Then run "aws sts get-caller-identity --profile sandbox". If it works AND the Account number equals the one I gave, skip to step 2. If the profile exists but shows a DIFFERENT account, it is an old or expired sandbox: do NOT use it, tell me, and fix the profile as below. If any later call fails with "explicit deny in a service control policy" (for example p-1lb4bh9n), do NOT ask me to contact an administrator: first check that the Account ID is my current active lease, because an old account that was returned to the pool is blocked on purpose. Back up ~/.aws/config, then add these blocks (if a profile named sandbox exists, show me and ask first):
[sso-session sandbox]
sso_start_url = https://eliteacademy.awsapps.com/start
sso_region = ap-southeast-1
sso_registration_scopes = sso:account:access
[profile sandbox]
sso_session = sandbox
sso_account_id = <MY ACCOUNT ID>
sso_role_name = myisb_IsbUsersPS
region = ap-southeast-5
output = json
Then run: aws sso login --profile sandbox . A browser opens: tell me to click Allow, then wait. Finally run aws sts get-caller-identity --profile sandbox and show the Account ID. It must equal the one I gave. If the session expires later (ExpiredToken), run the login again and continue.
2. CONNECT THE AWS MCP SERVER (optional helper). Create or merge .kiro/settings/mcp.json in this project with a server named aws-mcp-sandbox: command uvx, timeout 100000, transport stdio, args ["mcp-proxy-for-aws@latest", "https://aws-mcp.us-east-1.api.aws/mcp", "--profile", "sandbox", "--metadata", "AWS_REGION=ap-southeast-5"]. Keep any other servers already in the file. If the server does not show up as connected, do not wait: continue with the normal aws and sam commands, and tell me I can reload MCP servers later.
3. READ THE PROJECT. Read .github/workflows/deploy.yml and infra/template.yaml. Report the stack name, the template path, and every placeholder like __URL_*__ in frontend/index.html.
4. FIX OLD REGION AND MODELS. Search the whole project for "ap-southeast-1" and other hard-coded regions, and for old model IDs. Change them to ap-southeast-5 in infra/template.yaml and .github/workflows/deploy.yml (also the Bedrock IAM ARNs). Use only these model IDs: global.anthropic.claude-haiku-4-5-20251001-v1:0 (recommended), global.anthropic.claude-haiku-5-5 (only if it works), global.anthropic.claude-sonnet-5-5, global.amazon.nova-2-lite-v1:0. For each model the IAM policy needs three ARNs: arn:aws:bedrock:ap-southeast-5:<ACCOUNT_ID>:inference-profile/<id>, arn:aws:bedrock:ap-southeast-5::foundation-model/<base id without global.>, and arn:aws:bedrock:::foundation-model/<base id without global.>. Show me a short summary of what you changed.
5. CHECK THE MODELS. With aws bedrock-runtime converse in ap-southeast-5 (maxTokens 20, message "hi"), test these in order and show each result: global.anthropic.claude-haiku-4-5-20251001-v1:0, global.anthropic.claude-haiku-5-5, global.anthropic.claude-sonnet-5-5, global.amazon.nova-2-lite-v1:0. Use the FIRST one that answers as the app's default model: set it wherever the project defines its model ID (code, template environment variable, or config), so the app works today. Do not stop to ask me about this. If a model fails, quote the exact error and use this table: "Model use case details have not been submitted" = this account has not filled the Anthropic use-case form yet (tell me; I can fill it later in the Bedrock console, or you can submit it with aws bedrock put-use-case-for-model-access only after I give you the five answers: company name, website, intended users, industry, use case); "explicit deny" = the sandbox blocks that model, do not try to bypass it; "model identifier is invalid" = wrong model ID or not offered in Malaysia.
6. BUILD AND DEPLOY. Run sam build --template infra/template.yaml, then sam deploy --stack-name <stack from deploy.yml> --resolve-s3 --capabilities CAPABILITY_IAM CAPABILITY_NAMED_IAM --region ap-southeast-5 --profile sandbox --no-confirm-changeset --no-fail-on-empty-changeset. Do NOT use the GitHub secrets or --s3-bucket. IMPORTANT: Lambda Function URLs (FunctionUrlConfig) do not exist in ap-southeast-5. If the template uses them, replace them with an AWS::Serverless::HttpApi (CORS *) and an HttpApi event per function, keep the same URL placeholders, and tell me what you changed.
7. WEBSITE. Read the stack outputs. Replace every __URL_*__ placeholder in frontend/index.html with the matching output URL (same logic as the workflow). If the file contains old real URLs or an old Account ID instead of placeholders, replace those too. Then upload with aws s3 sync frontend/ s3://<FrontendBucketName>/ --cache-control no-cache --profile sandbox --region ap-southeast-5.
8. TEST. Call the backend URL with curl (POST, JSON body {"prompt":"Say hi in five words"}) and fetch the FrontendUrl with curl. Show the HTTP status and the first lines of each response.
9. REPORT. Finish with a table: Account ID, region, stack status, FrontendUrl, backend URL result, default model, files you changed. List anything I must do myself (for example the Anthropic form or GitHub secrets).
When something fails, or you want to understand a result, just ask Kiro:
deploy.yml or template.yaml still names the Singapore region, change every occurrence to ap-southeast-5 before you deploy. Kiro does this search for you in the prompt above. To do it yourself (from your project folder):
grep -rn "ap-southeast-1" --include=*.yml --include=*.yaml --include=*.py --include=*.html .
Typical places are --region in the sam deploy step, aws-region: in the credentials step, and Bedrock ARNs in template.yaml. Singapore still works for the old app, but your models and guide steps are written for Malaysia.template.yaml contains FunctionUrlConfig (older apps), sam deploy fails there. Replace it with an API Gateway HTTP API. Add one resource and change each function:
AppHttpApi:
Type: AWS::Serverless::HttpApi
Properties:
CorsConfiguration:
AllowOrigins: ['*']
AllowHeaders: ['*']
AllowMethods: [POST, OPTIONS]
MyFunction:
Type: AWS::Serverless::Function
Properties:
# ...keep everything else, but delete FunctionUrlConfig and AWS_LWA_INVOKE_MODE
Timeout: 25
Events:
Http:
Type: HttpApi
Properties:
ApiId: !Ref AppHttpApi
Path: /my-widget
Method: POST
Outputs:
MyApiUrl:
Value: !Sub https://${AppHttpApi}.execute-api.${AWS::Region}.amazonaws.com/my-widget
The answer now arrives all at once (no word-by-word streaming) and a request may take at most 30 seconds. The prompt above already tells Kiro to do this for you. You can also ask it: "Replace FunctionUrlConfig with an HTTP API as in the guide."Only if you want every commit to redeploy by itself. Kiro already put your app online in Step 3, so you can skip this.
B1. Create the deploy user, keys and bucket. Click the CloudShell icon (>_) in the top bar of the AWS console, wait for the prompt, and run:
REGION=ap-southeast-5
ACCOUNT=$(aws sts get-caller-identity --query Account --output text)
aws iam create-user --user-name github-deployer
for P in AWSCloudFormationFullAccess AWSLambda_FullAccess IAMFullAccess \
AmazonAPIGatewayAdministrator AmazonS3FullAccess AmazonBedrockFullAccess; do
aws iam attach-user-policy --user-name github-deployer \
--policy-arn arn:aws:iam::aws:policy/$P
done
aws iam create-access-key --user-name github-deployer \
--query 'AccessKey.[AccessKeyId,SecretAccessKey]' --output text
aws s3 mb s3://sam-deploy-$ACCOUNT-$REGION --region $REGION
B2. Update your GitHub secrets. First see which secrets your workflow uses (search secrets. in deploy.yml on GitHub):
grep -o 'secrets\.[A-Z_]*' .github/workflows/deploy.yml | sort -u
In your repository open Settings β Secrets and variables β Actions. The old secrets already exist, so click the pencil icon β Update on each one (do not create duplicates):
| Secret | New value |
|---|---|
AWS_ACCESS_KEY_ID | The new Access Key ID from B1 |
AWS_SECRET_ACCESS_KEY | The new Secret Access Key from B1 |
SAM_DEPLOY_BUCKET | sam-deploy-YOUR-ACCOUNT-ID-ap-southeast-5 (the bucket you just created) |
AWS_REGION (only if your workflow uses it) | Your region, for example ap-southeast-5 |
API_KEY_VALUE (only if your workflow uses it) | Keep the same value, so your frontend key stays correct |
B3. Run the workflow. GitHub β Actions β your workflow β Run workflow. Wait 3β5 minutes for every step to turn green, then open the Print URLs step and copy the API URL and Frontend URL.
Your website talks to your backend through addresses that are different in every account. There are two cases:
| What your files look like | What to do |
|---|---|
frontend/index.html contains placeholders such as __URL_MY_FUNCTION__, and deploy.yml has sed -i β¦ lines | β Nothing. The deployment injects the new addresses by itself every time. (Default setup.) |
frontend/index.html contains a real, old address (it looks like https://abc123.execute-apiβ¦ or https://abc123.lambda-urlβ¦on.aws) | β οΈ Replace it with the new address, as below. |
Kiro checks this for you in Step 3. To check it yourself (from your project folder):
grep -n "__URL_\|__API" frontend/index.html
grep -n "sed -i" .github/workflows/deploy.yml
Find every old value that points to the previous account:
grep -rnE "[0-9]{12}|execute-api|lambda-url|cloudfront.net|s3-website" \
--include=*.html --include=*.py --include=*.yaml --include=*.yml .
A 12-digit number is usually your old Account ID. execute-api and lambda-url are old backend addresses. (Some matches, like timestamps, are harmless.) Anything that points to the old account must be changed.
To replace an old address, ask Kiro, sharing frontend/index.html:
frontend/index.html to GitHub. The workflow redeploys by itself.| If your app used⦠| Do this |
|---|---|
| DynamoDB (chat history, saved results) | The table is created empty by your template. Data from the old account is gone. Re-seed it if you need sample data. |
| HTTPS with CloudFront (main tutorial Step 9) | Repeat Step 9. You get a new CloudFront domain, and any custom domain must be pointed at it again. |
| WAF, alarms, custom domain | Create them again. They do not carry over. |
FrontendUrl) opens in a browser/aws/lambda/your-function shows no errors| What you see | Why | Fix |
|---|---|---|
| explicit deny in a service control policy | Region not allowed, or a blocked model (Opus) | Use one of the five regions in Step 1. Use a model from the table in Step 2. |
| The provided model identifier is invalid | The model is not offered in this region (for example Claude 3 Haiku or Llama 3 in Malaysia) | Use a model ID from the table in Step 2 |
| on-demand throughput isnβt supported | Plain model ID used | Use the global. ID from Step 2 |
| Lambda AccessDenied β¦ bedrock:InvokeModel (no mention of a service control policy) | Function role lacks Bedrock permission | Add the policy block from Step 2 to template.yaml |
| The security token included in the request is invalid / Credentials could not be loaded | GitHub still holds keys from the old account | Update the two AWS key secrets (Path B, B2). No spaces in the values. |
| NoSuchBucket / Bucket does not exist | SAM_DEPLOY_BUCKET still names the old (deleted) bucket | Update the secret, or use --resolve-s3 (what the Kiro prompt does) |
| BucketAlreadyExists | S3 names are unique worldwide | Add your Account ID to the bucket name |
| Stack β¦ is in ROLLBACK_COMPLETE state and can not be updated | A first deploy failed half-way | CloudFormation β select the stack β Delete, wait, then deploy again |
| Website opens, but requests fail or time out | The frontend still calls an old backend address | Do Step 4 |
The page shows or calls something like __URL_MY_FUNCTION__ | The URL-injection lines did not run | Ask Kiro: "Inject the stack output URLs into frontend/index.html and upload it again." With GitHub Actions: re-run the workflow. |
| 403 Forbidden from your API (only if your app uses an API key) | The key in the frontend does not match API_KEY_VALUE | Compare both values exactly (no spaces) |
explicit deny in a service control policy β¦ p-1lb4bh9n (on every region and every service) | You are signed in to an OLD sandbox account that was returned to the pool, not to your current lease | Open the Innovation Sandbox web app β your Active lease β copy the Account ID. Tell Kiro: "My Account ID is 123456789012. Fix the sandbox profile so it points to this account and sign in again." |
| anthropic.claude-haiku-5-5 (or sonnet-5-5) is not available for this account | AWS enables the newest Claude models account by account. Nothing is wrong with your app | Use Claude Haiku 4.5 (or Nova 2 Lite). Ask your coach to request access from AWS if you really need the newer model |
| Model use case details have not been submitted for this account | A new account has not filled the one-time Anthropic form. Haiku 4.5 is blocked until the form is filled in the Malaysia region (it may work for a few minutes after the account is created, then stop). Amazon Nova 2 Lite keeps working | Use Nova 2 Lite for now, or open Bedrock in the console, choose a Claude model, click Submit use case details and complete the form (ask your coach for the company details), then wait up to 15 minutes |
| Kiro: 0 of 1 MCP servers initialized | Kiro cannot find uvx | Install uv, then use the full path from which uvx / where uvx in mcp.json |
| The SSO session associated with this profile has expired / Unable to locate credentials | Your terminal sign-in ended, or the profile was never created | Tell Kiro: "Run aws sso login --profile sandbox and continue" (if the profile is missing, ask Kiro to set up the sandbox sign-in from Step 3 again) |
aws sts get-caller-identity shows an old or unexpected account | The profile points to your previous account | Re-run aws configure sso and pick the new account, using the profile name sandbox |
| Console asks you to sign in again | The 1-hour console session ended | Reopen from eliteacademy.awsapps.com/start |
| Innovation Sandbox app says Session expired | Login timed out (or an old tab) | Click Login Again, or use the sign-in portal |
| Everything stops, the account looks frozen | The team budget limit was reached | Tell your coach. Delete what you do not need. |
aws dynamodb scan --table-name YOUR-TABLE > backup.json, then keep the file in your repository (never keep the only copy inside AWS).REDEPLOY.md in your repository with your stack name, region and the exact deploy commands Kiro used (ask Kiro: "Write REDEPLOY.md with the commands you ran").