agentarea-api migrate command. Both deployment targets run it automatically
before the API starts, so most of the time there is nothing to do. This guide
covers the cases where there is: inspecting what ran, applying migrations by
hand, and recovering a database that Alembic will not advance.
Migrations run from agentarea-platform/apps/api, never from the repository
root. alembic.ini sets script_location = alembic as a relative path, so
Alembic resolves the migration directory against the working directory. Both the
Kubernetes Job and the Compose service set working_dir: /app/apps/api for this
reason.
Prerequisites
- A reachable PostgreSQL instance with the
agentareadatabase created - For local work: Python 3.12 or later and
uv, from a clone of the repository - The same
DATABASE_URLorPOSTGRES_*values the platform uses
Steps
Understand what runs automatically
Both are ordered ahead of the API. Compose declares
app_migrations: condition: service_completed_successfully as a dependency of
app, so a failed migration keeps the API from starting rather than letting it
serve against a stale schema. On Kubernetes the Job has
ttlSecondsAfterFinished: 300 and disappears five minutes after it succeeds.agentarea-api migrate does more than alembic upgrade head:- It opens a connection and runs
SELECT 1, printingDatabase connection successful. - It reads the current Alembic revision.
- If there is no revision and the
provider_specstable exists, it treats the schema as already current and runsalembic stamp headinstead of replaying migrations. This is the path for a database created by an older bootstrap. - If there is no revision and no
provider_specstable, it runsalembic upgrade headfrom empty. - If there is a revision, it runs
alembic upgrade headnormally.
Migration failed: and exits 1.Apply migrations by hand
When you need to run them outside the normal startup path — after restoring a
backup, or against an external database the Job cannot reach.On Kubernetes, run a one-off pod from the API image:Or re-run the chart’s own Job by reinstalling with only that Job enabled.Under Compose:From a clone, against a database you can reach directly:
Inspect migration state
From The platform also exposes this as a command:Inside a running container:
agentarea-platform/apps/api:Create a migration
Only when changing the schema in code.
alembic.ini sets
file_template = %%(year)d%%(month).2d%%(day).2d_%%(hour).2d%%(minute).2d_%%(slug)s,
so new files are named by ISO-style timestamp — 20260729_1432_add_widget_table.py.
Do not rename them into any other scheme.Always read the generated file before committing. Autogenerate does not detect
every change, and it will happily drop a column it does not recognise.Verify
Confirm the database is at the revision the code expects — the two commands must print the same identifier:Migrations completed successfully, or Stamped database to head revision when the schema pre-existed. On Kubernetes:
1/1.
Confirm the schema is actually usable, not merely stamped:
Troubleshooting
The migration Job sits in Init:0/1 and logs Waiting for database...
The migration Job sits in Init:0/1 and logs Waiting for database...
Its
wait-for-db init container polls nc -z <host> <port> and never times
out. The host is global.database.host , or the bundled PostgreSQL service
when that is empty. Verify the host resolves from inside the namespace and
the port is reachable.Migration failed: with a relation already exists error
Migration failed: with a relation already exists error
Alembic is replaying a migration against a schema that already has the
object. This happens when a database has tables but no Stamping tells Alembic the database is current without checking. If the
schema is not in fact current, you have hidden the gap rather than
closed it; take a backup first.
alembic_version
row, and the auto-stamp path did not trigger because provider_specs
was absent — a “dirty” database, in the command’s own words. Confirm the
schema really is current, then stamp it:Can't locate revision identified by '<hash>'
Can't locate revision identified by '<hash>'
The database records a revision that does not exist in the image’s
migration directory — usually a downgrade to an older image after a
newer one migrated, or a branch whose migration was never merged. Roll
forward to the image that contains the revision. Do not delete the
alembic_version row to make the error go away; it strands the schema
at an unknown point.alembic branches returns rows
alembic branches returns rows
Two migrations claim the same parent, typically from two branches merged
without rebasing. Generate a merge revision:
Migrations work locally but fail in the container with FAILED: No 'script_location' key found
Migrations work locally but fail in the container with FAILED: No 'script_location' key found
The command ran from the repository root.
alembic.ini uses a relative
script_location , so the working directory must be
agentarea- platform/apps/api (/app/apps/api in the image).A helm upgrade leaves the API running an older schema
A helm upgrade leaves the API running an older schema
The migration Job is a normal resource, not a Helm hook — the chart notes
this is deliberate, to avoid a dependency deadlock with the database. It
therefore does not block the Deployment rollout. Check the Job completed
before assuming the upgrade is done. See [upgrades](/self- host/upgrades) .
Related
Deploy on Kubernetes with Helm
Install the agentarea Helm chart, decide which bundled dependencies to keep
Deploy with Docker Compose
Run the full AgentArea platform on one host with docker- compose.yaml
Upgrade a deployment
Move an AgentArea deployment to a new version safely
Back up and restore
Identify everything AgentArea stores, back each store up