LocalStack exited with code 55 after a routine image update
Posted in Docker, Aws, Debugging
By Dušan Dželebdžić

I was setting up a boring local SQS dependency for a new app. Docker Compose would start PostgreSQL, start LocalStack, create five queues and their dead-letter queues, then get out of the way.
LocalStack never became healthy.
Compose waited for the health check and eventually reported that the container had exited. Its exit code was 55. The useful bit was in the container log:
License activation failed!
Reason: No credentials were found in the environment.That was unexpected. I wasn't starting a Pro service. I wasn't asking LocalStack to emulate half of AWS. I needed SQS, locally, with fake credentials.
The Compose file looked like the usual Community setup, because until recently it was.
The image name stayed the same, but the contract changed
The image I tried was localstack/localstack:2026.07.3. The important part isn't that particular patch version. The change happened earlier.
Starting with LocalStack for AWS 2026.03.0, the old Community and Pro images were consolidated. Both Docker Hub names now point at the same product, and the services available inside it depend on the account behind an auth token.
An auth token is therefore no longer something you add only when you use paid features. LocalStack's current documentation calls it mandatory for starting the container.
The old mental model was:
localstack/localstack = Community, no account required
localstack/localstack-pro = paid features, auth requiredThe new model is:
localstack/localstack = unified image, auth required
localstack/localstack-pro = the same unified image, auth requiredMy configuration hadn't become invalid Docker Compose. The product behind the tag had changed its startup requirements.
Why the failure looks like a Docker problem
When Compose says a service is unhealthy or exited with code 55, several layers look suspicious first. Maybe the health command is wrong. Maybe port 4566 is occupied. Maybe Docker Desktop has done one of its little interpretive dances with the network again.
None of that applied here. LocalStack was intentionally terminating before it opened the service endpoint. A health check cannot pass when the process has decided it isn't licensed to start.
The quickest diagnostic is:
docker compose ps -a
docker compose logs localstackIf the last lines say License activation failed!, stop debugging ports and health intervals. The container has already told you which layer is broken.
LocalStack's FAQ also documents exit code 55 for startup failures. The text after Reason: matters because the same code can cover a missing token, an invalid license, or a licensing server that the container cannot reach.
The proper fix: authenticate
For a current image, create the appropriate LocalStack account and pass the token as a secret:
services:
localstack:
image: localstack/localstack:2026.07.3
environment:
LOCALSTACK_AUTH_TOKEN: ${LOCALSTACK_AUTH_TOKEN}
SERVICES: sqsDo not put the token itself in compose.yaml. Do not commit it in a helpful .env.example. The token identifies your LocalStack user or workspace and should be handled like any other development or CI credential.
LocalStack offers a free Hobby plan for non-commercial work. Commercial projects need the plan that matches their use. That distinction mattered for me because this wasn't a weekend demo. It was local infrastructure for a SaaS product.
There was also a temporary compatibility switch called LOCALSTACK_ACKNOWLEDGE_ACCOUNT_REQUIREMENT. It only postponed enforcement until 6 April 2026. Copying it into a new Compose file in August would be infrastructure archaeology, not a fix.
The option I chose for now
I didn't want every developer and CI runner to need a new external account just to boot five local SQS queues during the first implementation slice. I pinned the last pre-consolidation Community release, 4.14.0, with its exact digest:
services:
localstack:
# Local-only compatibility pin. Revisit before relying on LocalStack in CI.
image: localstack/localstack:4.14.0@sha256:3ebc37595918b8accb852f8048fef2aff047d465167edd655528065b07bc364a
environment:
SERVICES: sqs
PERSISTENCE: "0"That image starts without a LocalStack account. The ten queues were created, the health check passed, and local development became boring again.
But this is a pin, not a clever bypass.
LocalStack's own migration guidance lists staying on an older tagged release as an option and states the tradeoff plainly: you opt out of future updates and security patches. Version 4.14.0 was released on 26 February 2026, immediately before the new calendar-versioned unified releases began in March.
I documented four restrictions next to the pin:
- it is for local development only;
- it must never be promoted into the deployed AWS environment;
- the image is digest-pinned so a tag cannot silently change underneath us;
- adopting authenticated LocalStack or another SQS test double is a deliberate revisit, not an invisible upgrade.
That makes the debt visible. Someone changing the image later has enough context to understand why it was pinned and what must be decided.
Don't turn a licensing decision into a flaky build
The easy mistake is to change latest to whatever old version boots and move on. Six months later nobody remembers why the project is running an abandoned emulator.
The other easy mistake is to add a personal auth token to a shared .env file and accidentally make one developer's account part of the build system.
Pick the dependency model on purpose:
- Use current LocalStack: authenticate local and CI runs, manage token rotation, and pay for the commercial plan you need.
- Pin Community 4.14.0: keep unauthenticated local SQS for now, record the lack of updates, and keep it away from production.
- Replace it: use a narrower SQS test double or test against an isolated AWS account when the old pin becomes more liability than convenience.
The correct choice depends on what LocalStack is doing for you. Pretending the March 2026 change didn't happen isn't one of the choices.
Takeaway
If LocalStack suddenly exits with code 55 and License activation failed!, your SQS config probably isn't the problem. Current images require authentication before any emulated service starts.
Add a real auth token, or pin the old Community image with a written expiry plan. What you shouldn't do is leave a floating image tag in a critical local workflow and let a licensing change arrive disguised as a broken health check.
Version tags are part of the interface. Treat them that way.
Did a routine dependency update quietly change the rules? Send me the error and I'll take a look.