[GH-ISSUE #24129] issue: Database migration fails with UniqueViolation and DuplicateTable errors when upgrading to latest version #90937

Open
opened 2026-05-15 16:13:55 -05:00 by GiteaMirror · 3 comments
Owner

Originally created by @juanpabloequihua on GitHub (Apr 25, 2026).
Original GitHub issue: https://github.com/open-webui/open-webui/issues/24129

Check Existing Issues

  • I have searched for any existing and/or related issues.
  • I have searched for any existing and/or related discussions.
  • I have also searched in the CLOSED issues AND CLOSED discussions and found no related items (your issue might already be addressed on the development branch!).
  • I am using the latest version of Open WebUI.

Installation Method

Docker

Open WebUI Version

General Version v0.9.2

Ollama Version (if applicable)

No response

Operating System

Debian GNU/Linux

Browser (if applicable)

No response

Confirmation

  • I have read and followed all instructions in README.md.
  • I am using the latest version of both Open WebUI and Ollama.
  • I have included the browser console logs.
  • I have included the Docker container logs.
  • I have provided every relevant configuration, setting, and environment variable used in my setup.
  • I have clearly listed every relevant configuration, custom setting, environment variable, and command-line option that influences my setup (such as Docker Compose overrides, .env values, browser settings, authentication configurations, etc).
  • I have documented step-by-step reproduction instructions that are precise, sequential, and leave nothing to interpretation. My steps:
  • Start with the initial platform/version/OS and dependencies used,
  • Specify exact install/launch/configure commands,
  • List URLs visited, user input (incl. example values/emails/passwords if needed),
  • Describe all options and toggles enabled or changed,
  • Include any files or environmental changes,
  • Identify the expected and actual result at each stage,
  • Ensure any reasonably skilled user can follow and hit the same issue.

Expected Behavior

Expected Behavior

Database migrations should run successfully regardless of:

  • The current state of the database (whether objects already exist or not)
  • The size of the database
  • Whether a previous migration attempt partially completed and failed

Specifically:

  • Migration scripts should check if tables, columns, and indexes already exist
    before attempting to create them
  • Data migration steps (such as inserting access_grant records in migration
    c1d2e3f4a5b6) should check for duplicate records before inserting and
    gracefully skip them if they already exist
  • If a migration fails midway and is re-run, it should be able to resume cleanly
    without crashing on already-created database objects
  • The application should start successfully after pulling the latest Docker image
    without requiring manual database intervention

Actual Behavior

Actual Behavior

The migration chain fails with multiple errors on a large PostgreSQL database (100GB+)
that has existing shared chats and data accumulated over time.

The failure occurs in two distinct ways:

1. UniqueViolation (migration c1d2e3f4a5b6)

The migration script loops through all existing shared chats and attempts to insert
a read permission record into the access_grant table for each one. Because the
database already contains these records from a previous partial migration attempt,
the plain INSERT statement crashes with:
sqlalchemy.exc.IntegrityError: (psycopg2.errors.UniqueViolation)
duplicate key value violates unique constraint "uq_access_grant_grant"

2. DuplicateTable errors (migrations d4e5f6a7b8c9 and 56359461a091)

When the migration chain crashes midway, some tables are created but the Alembic
version is never updated. On the next migration attempt, the scripts try to create
those tables again, resulting in:
sqlalchemy.exc.ProgrammingError: (psycopg2.errors.DuplicateTable)
relation "automation" already exists

sqlalchemy.exc.ProgrammingError: (psycopg2.errors.DuplicateTable)
relation "calendar" already exists

3. Inconsistent database state

The combination of the above errors leaves the database in an inconsistent state
where:

  • Some tables exist but are not registered in Alembic's version history
  • Some columns are missing from existing tables (e.g. tasks, summary,
    last_read_at, is_pinned)
  • The application crashes on startup with errors such as:
    psycopg.errors.UndefinedColumn: column "tasks" of relation "chat" does not exist
    psycopg.errors.UndefinedTable: relation "automation" does not exist

4. Recovery requires complex manual intervention

Recovering from this state required:

  1. Manually entering the Docker container
  2. Editing multiple migration files to add existence checks
  3. Manually manipulating the Alembic version stamp to force re-execution of migrations

Note: The database size (100GB+) is likely a contributing factor as it increases
the number of shared chats and accumulated data, making duplicate record conflicts
more likely to occur during data migration steps.

Steps to Reproduce

Steps to Reproduce

  1. Have a running Open WebUI instance with:

    • A large PostgreSQL database (100GB+)
    • Existing shared chats accumulated over time
    • A previous stable version of the Docker image running successfully
  2. Pull the latest Docker image:

    docker pull ghcr.io/open-webui/open-webui:main
    
  3. Stop the current container:

    docker stop open-webui
    
  4. Start a new container with the latest image:

    docker start open-webui
    
  5. Check the container logs:

    docker logs open-webui
    
  6. Observe the migration errors in the logs. The failure chain is:

    • Migration c1d2e3f4a5b6 crashes with UniqueViolation
    • This leaves the database in an inconsistent state
    • Subsequent restart attempts fail with DuplicateTable errors
    • The application becomes partially unusable:
      • Existing chats are inaccessible
      • Sending new messages fails with UndefinedColumn errors
      • Automation features fail with UndefinedTable errors

Logs & Screenshots

Logs

Initial migration failure (container logs)

INFO  [alembic.runtime.migration] Context impl PostgresqlImpl.
INFO  [alembic.runtime.migration] Will assume transactional DDL.
INFO  [alembic.runtime.migration] Running upgrade b2c3d4e5f6a7 -> a3dd5bedd151, Add tasks and summary columns to chat table
INFO  [alembic.runtime.migration] Running upgrade a3dd5bedd151 -> d4e5f6a7b8c9, add automation tables
INFO  [alembic.runtime.migration] Running upgrade d4e5f6a7b8c9 -> b7c8d9e0f1a2, add last_read_at to chat
INFO  [alembic.runtime.migration] Running upgrade b7c8d9e0f1a2 -> e1f2a3b4c5d6, Add is_pinned to note table
INFO  [alembic.runtime.migration] Running upgrade e1f2a3b4c5d6 -> c1d2e3f4a5b6, Add shared_chat table and migrate existing shares
ERROR [open_webui.env] Error running migrations: (psycopg2.errors.UniqueViolation) 
duplicate key value violates unique constraint "uq_access_grant_grant"
DETAIL:  Key (resource_type, resource_id, principal_type, principal_id, permission)=
(shared_chat, f4fe05cd-be32-4090-9e6c-73d4c58577a5, user, *, read) already exists.
[SQL: INSERT INTO access_grant (id, resource_type, resource_id, principal_type, 
principal_id, permission, created_at) VALUES (%(id)s, %(resource_type)s, 
%(resource_id)s, %(principal_type)s, %(principal_id)s, %(permission)s, %(created_at)s)]

DuplicateTable error after partial migration (subsequent restart attempt)

sqlalchemy.exc.ProgrammingError: (psycopg2.errors.DuplicateTable) 
relation "automation" already exists
[SQL: 
CREATE TABLE automation (
        id TEXT NOT NULL, 
        user_id TEXT NOT NULL, 
        name TEXT NOT NULL, 
        data JSON NOT NULL,
        ...
)
]

### DuplicateTable error for calendar tables

sqlalchemy.exc.ProgrammingError: (psycopg2.errors.DuplicateTable)
relation "calendar" already exists
[SQL:
CREATE TABLE calendar (
id TEXT NOT NULL,
user_id TEXT NOT NULL,
name TEXT NOT NULL,
color TEXT,
is_default BOOLEAN NOT NULL,
...
)
]

Application errors after inconsistent migration state

# When trying to access existing chats:
sqlalchemy.exc.InternalError: (psycopg.errors.InFailedSqlTransaction) 
current transaction is aborted, commands ignored until end of transaction block

# When trying to send a new message:
psycopg.errors.UndefinedColumn: column "tasks" of relation "chat" does not exist
LINE 1: ..._at, share_id, archived, pinned, meta, folder_id, tasks, sum...
[SQL: INSERT INTO chat (id, user_id, title, chat, created_at, updated_at, 
share_id, archived, pinned, meta, folder_id, tasks, summary, last_read_at) 
VALUES (...)]

# When automation features are triggered:
sqlalchemy.exc.ProgrammingError: (psycopg2.errors.UndefinedTable) 
relation "automation" does not exist
LINE 2: FROM automation

Additional Information

Additional Information

Database Details

  • Database engine: PostgreSQL (via psycopg2)
  • Database size: 100GB+
  • Data accumulated: Several months of chat history with multiple shared chats
  • The large database size is likely a contributing factor as it increases the number
    of existing shared chat records, making the UniqueViolation in migration
    c1d2e3f4a5b6 more likely to occur

Deployment Details

  • Deployment method: Docker container on a Linux VM
  • Image used: ghcr.io/open-webui/open-webui:main

Affected Migration Files

All of the following migration scripts lack existence checks:

Revision ID Description Error Type
a3dd5bedd151 Add tasks and summary columns to chat table DuplicateColumn
d4e5f6a7b8c9 Add automation tables DuplicateTable
b7c8d9e0f1a2 Add last_read_at to chat DuplicateColumn
e1f2a3b4c5d6 Add is_pinned to note table DuplicateColumn
c1d2e3f4a5b6 Add shared_chat table and migrate existing shares UniqueViolation
56359461a091 Add calendar tables DuplicateTable

Complete Workaround & Solution

The following steps were required to fully recover from the broken migration state.
This is documented here in detail to help other users who encounter the same issue
and to provide the maintainers with a clear picture of the impact on end users.

Step 1: Enter the Docker container

docker exec -it open-webui bash

Step 2: Export required environment variables

The migration scripts require these two environment variables to initialize
the application environment. Without them, Alembic will fail with
ValueError: Required environment variable not found:

export DATABASE_URL="postgresql://user:password@host:5432/dbname"
export WEBUI_SECRET_KEY="your_secret_key"
cd /app/backend/open_webui

Step 3: Edit all affected migration files

Each migration file needs to be updated to add existence checks before creating
or inserting database objects. The files are located at:

/app/backend/open_webui/migrations/versions/

The required code changes for each file are as follows:

Fix for table creation (migrations d4e5f6a7b8c9 and 56359461a091):

conn = op.get_bind()

# Wrap every create_table call with an existence check
if not conn.dialect.has_table(conn, 'table_name'):
    op.create_table('table_name', ...)

# Wrap every create_index call with an existence check
result = conn.execute(sa.text(
    "SELECT indexname FROM pg_indexes "
    "WHERE tablename='table_name' AND indexname='index_name'"
))
if result.fetchone() is None:
    op.create_index('index_name', 'table_name', ['column_name'])

Fix for column addition (migrations a3dd5bedd151, b7c8d9e0f1a2, e1f2a3b4c5d6):

conn = op.get_bind()

# Wrap every add_column call with an existence check
result = conn.execute(sa.text(
    "SELECT column_name FROM information_schema.columns "
    "WHERE table_name='table_name' AND column_name='column_name'"
))
if result.fetchone() is None:
    op.add_column('table_name', sa.Column('column_name', ...))

Fix for duplicate data inserts (migration c1d2e3f4a5b6):

# Before every INSERT into access_grant, check if the record already exists
existing_grant = conn.execute(
    sa.select(access_grant_t.c.id).where(
        sa.and_(
            access_grant_t.c.resource_type == 'shared_chat',
            access_grant_t.c.resource_id == original_chat_id,
            access_grant_t.c.principal_type == 'user',
            access_grant_t.c.principal_id == '*',
            access_grant_t.c.permission == 'read',
        )
    )
).fetchone()

if not existing_grant:
    conn.execute(access_grant_t.insert().values(...))

# Also check before every INSERT into shared_chat
existing_shared = conn.execute(
    sa.select(shared_chat_t.c.id).where(
        shared_chat_t.c.id == share_token
    )
).fetchone()

if not existing_shared:
    conn.execute(shared_chat_t.insert().values(...))

Step 4: Roll back the Alembic stamp to the last known good migration

This is necessary to force Alembic to re-execute all the migrations that were
partially applied or skipped. The last known good migration before the failures
began was b2c3d4e5f6a7:

cd /app/backend/open_webui
alembic stamp b2c3d4e5f6a7

Step 5: Re-run the migrations

alembic upgrade head

A successful run should show all 6 migrations completing without errors:

INFO  [alembic.runtime.migration] Running upgrade b2c3d4e5f6a7 -> a3dd5bedd151, Add tasks and summary columns to chat table
INFO  [alembic.runtime.migration] Running upgrade a3dd5bedd151 -> d4e5f6a7b8c9, add automation tables
INFO  [alembic.runtime.migration] Running upgrade d4e5f6a7b8c9 -> b7c8d9e0f1a2, add last_read_at to chat
INFO  [alembic.runtime.migration] Running upgrade b7c8d9e0f1a2 -> e1f2a3b4c5d6, Add is_pinned to note table
INFO  [alembic.runtime.migration] Running upgrade e1f2a3b4c5d6 -> c1d2e3f4a5b6, Add shared_chat table and migrate existing shares
INFO  [alembic.runtime.migration] Running upgrade c1d2e3f4a5b6 -> 56359461a091, add calendar tables

Step 6: Restart the container

exit
docker restart open-webui
docker logs -f open-webui

Impact Assessment

This bug has a significant impact on production deployments:

  • Application becomes completely unusable after pulling the latest image
  • Existing chats are inaccessible due to failed SQL transactions
  • New messages cannot be sent due to missing columns
  • Automation features fail due to missing tables
  • Recovery requires deep technical knowledge of Docker, PostgreSQL,
    SQLAlchemy and Alembic - not suitable for non-technical users
  • Risk of data loss if users attempt a database downgrade without
    fully understanding the consequences
  • No data was lost in this specific case after applying the manual fix

Recommendation

In addition to fixing the individual migration scripts, we recommend considering
the following improvements to make the migration system more robust:

  1. Add existence checks to all future migration scripts as a standard practice
  2. Add a pre-migration validation step that checks the current state of the
    database before running migrations and warns the user if inconsistencies are found
  3. Improve error messages to guide users through recovery steps when a
    migration fails
  4. Add migration rollback handling so that if a migration fails midway,
    the database is automatically restored to its previous consistent state
  5. Add integration tests that simulate partial migration failures to catch
    these issues before release
Originally created by @juanpabloequihua on GitHub (Apr 25, 2026). Original GitHub issue: https://github.com/open-webui/open-webui/issues/24129 ### Check Existing Issues - [x] I have searched for any existing and/or related issues. - [x] I have searched for any existing and/or related discussions. - [x] I have also searched in the CLOSED issues AND CLOSED discussions and found no related items (your issue might already be addressed on the development branch!). - [x] I am using the latest version of Open WebUI. ### Installation Method Docker ### Open WebUI Version General Version v0.9.2 ### Ollama Version (if applicable) _No response_ ### Operating System Debian GNU/Linux ### Browser (if applicable) _No response_ ### Confirmation - [x] I have read and followed all instructions in `README.md`. - [x] I am using the latest version of **both** Open WebUI and Ollama. - [x] I have included the browser console logs. - [x] I have included the Docker container logs. - [x] I have **provided every relevant configuration, setting, and environment variable used in my setup.** - [x] I have clearly **listed every relevant configuration, custom setting, environment variable, and command-line option that influences my setup** (such as Docker Compose overrides, .env values, browser settings, authentication configurations, etc). - [x] I have documented **step-by-step reproduction instructions that are precise, sequential, and leave nothing to interpretation**. My steps: - Start with the initial platform/version/OS and dependencies used, - Specify exact install/launch/configure commands, - List URLs visited, user input (incl. example values/emails/passwords if needed), - Describe all options and toggles enabled or changed, - Include any files or environmental changes, - Identify the expected and actual result at each stage, - Ensure any reasonably skilled user can follow and hit the same issue. ### Expected Behavior ## Expected Behavior Database migrations should run successfully regardless of: - The current state of the database (whether objects already exist or not) - The size of the database - Whether a previous migration attempt partially completed and failed Specifically: - Migration scripts should check if tables, columns, and indexes already exist before attempting to create them - Data migration steps (such as inserting `access_grant` records in migration `c1d2e3f4a5b6`) should check for duplicate records before inserting and gracefully skip them if they already exist - If a migration fails midway and is re-run, it should be able to resume cleanly without crashing on already-created database objects - The application should start successfully after pulling the latest Docker image without requiring manual database intervention ### Actual Behavior ## Actual Behavior The migration chain fails with multiple errors on a large PostgreSQL database (100GB+) that has existing shared chats and data accumulated over time. The failure occurs in two distinct ways: ### 1. UniqueViolation (migration c1d2e3f4a5b6) The migration script loops through all existing shared chats and attempts to insert a `read` permission record into the `access_grant` table for each one. Because the database already contains these records from a previous partial migration attempt, the plain `INSERT` statement crashes with: sqlalchemy.exc.IntegrityError: (psycopg2.errors.UniqueViolation) duplicate key value violates unique constraint "uq_access_grant_grant" ### 2. DuplicateTable errors (migrations d4e5f6a7b8c9 and 56359461a091) When the migration chain crashes midway, some tables are created but the Alembic version is never updated. On the next migration attempt, the scripts try to create those tables again, resulting in: sqlalchemy.exc.ProgrammingError: (psycopg2.errors.DuplicateTable) relation "automation" already exists sqlalchemy.exc.ProgrammingError: (psycopg2.errors.DuplicateTable) relation "calendar" already exists ### 3. Inconsistent database state The combination of the above errors leaves the database in an inconsistent state where: - Some tables exist but are not registered in Alembic's version history - Some columns are missing from existing tables (e.g. `tasks`, `summary`, `last_read_at`, `is_pinned`) - The application crashes on startup with errors such as: psycopg.errors.UndefinedColumn: column "tasks" of relation "chat" does not exist psycopg.errors.UndefinedTable: relation "automation" does not exist ### 4. Recovery requires complex manual intervention Recovering from this state required: 1. Manually entering the Docker container 2. Editing multiple migration files to add existence checks 3. Manually manipulating the Alembic version stamp to force re-execution of migrations **Note:** The database size (100GB+) is likely a contributing factor as it increases the number of shared chats and accumulated data, making duplicate record conflicts more likely to occur during data migration steps. ### Steps to Reproduce ## Steps to Reproduce 1. Have a running Open WebUI instance with: - A large PostgreSQL database (100GB+) - Existing shared chats accumulated over time - A previous stable version of the Docker image running successfully 2. Pull the latest Docker image: ```bash docker pull ghcr.io/open-webui/open-webui:main ``` 3. Stop the current container: ```bash docker stop open-webui ``` 4. Start a new container with the latest image: ```bash docker start open-webui ``` 5. Check the container logs: ```bash docker logs open-webui ``` 6. Observe the migration errors in the logs. The failure chain is: - Migration `c1d2e3f4a5b6` crashes with `UniqueViolation` - This leaves the database in an inconsistent state - Subsequent restart attempts fail with `DuplicateTable` errors - The application becomes partially unusable: - Existing chats are inaccessible - Sending new messages fails with `UndefinedColumn` errors - Automation features fail with `UndefinedTable` errors ### Logs & Screenshots ## Logs ### Initial migration failure (container logs) ``` INFO [alembic.runtime.migration] Context impl PostgresqlImpl. INFO [alembic.runtime.migration] Will assume transactional DDL. INFO [alembic.runtime.migration] Running upgrade b2c3d4e5f6a7 -> a3dd5bedd151, Add tasks and summary columns to chat table INFO [alembic.runtime.migration] Running upgrade a3dd5bedd151 -> d4e5f6a7b8c9, add automation tables INFO [alembic.runtime.migration] Running upgrade d4e5f6a7b8c9 -> b7c8d9e0f1a2, add last_read_at to chat INFO [alembic.runtime.migration] Running upgrade b7c8d9e0f1a2 -> e1f2a3b4c5d6, Add is_pinned to note table INFO [alembic.runtime.migration] Running upgrade e1f2a3b4c5d6 -> c1d2e3f4a5b6, Add shared_chat table and migrate existing shares ERROR [open_webui.env] Error running migrations: (psycopg2.errors.UniqueViolation) duplicate key value violates unique constraint "uq_access_grant_grant" DETAIL: Key (resource_type, resource_id, principal_type, principal_id, permission)= (shared_chat, f4fe05cd-be32-4090-9e6c-73d4c58577a5, user, *, read) already exists. [SQL: INSERT INTO access_grant (id, resource_type, resource_id, principal_type, principal_id, permission, created_at) VALUES (%(id)s, %(resource_type)s, %(resource_id)s, %(principal_type)s, %(principal_id)s, %(permission)s, %(created_at)s)] ``` ### DuplicateTable error after partial migration (subsequent restart attempt) ``` sqlalchemy.exc.ProgrammingError: (psycopg2.errors.DuplicateTable) relation "automation" already exists [SQL: CREATE TABLE automation ( id TEXT NOT NULL, user_id TEXT NOT NULL, name TEXT NOT NULL, data JSON NOT NULL, ... ) ] ### DuplicateTable error for calendar tables ``` sqlalchemy.exc.ProgrammingError: (psycopg2.errors.DuplicateTable) relation "calendar" already exists [SQL: CREATE TABLE calendar ( id TEXT NOT NULL, user_id TEXT NOT NULL, name TEXT NOT NULL, color TEXT, is_default BOOLEAN NOT NULL, ... ) ] ### Application errors after inconsistent migration state ``` # When trying to access existing chats: sqlalchemy.exc.InternalError: (psycopg.errors.InFailedSqlTransaction) current transaction is aborted, commands ignored until end of transaction block # When trying to send a new message: psycopg.errors.UndefinedColumn: column "tasks" of relation "chat" does not exist LINE 1: ..._at, share_id, archived, pinned, meta, folder_id, tasks, sum... [SQL: INSERT INTO chat (id, user_id, title, chat, created_at, updated_at, share_id, archived, pinned, meta, folder_id, tasks, summary, last_read_at) VALUES (...)] # When automation features are triggered: sqlalchemy.exc.ProgrammingError: (psycopg2.errors.UndefinedTable) relation "automation" does not exist LINE 2: FROM automation ``` ### Additional Information ## Additional Information ### Database Details - **Database engine:** PostgreSQL (via psycopg2) - **Database size:** 100GB+ - **Data accumulated:** Several months of chat history with multiple shared chats - The large database size is likely a contributing factor as it increases the number of existing shared chat records, making the `UniqueViolation` in migration `c1d2e3f4a5b6` more likely to occur ### Deployment Details - **Deployment method:** Docker container on a Linux VM - **Image used:** `ghcr.io/open-webui/open-webui:main` ### Affected Migration Files All of the following migration scripts lack existence checks: | Revision ID | Description | Error Type | |-------------|-------------|------------| | `a3dd5bedd151` | Add tasks and summary columns to chat table | DuplicateColumn | | `d4e5f6a7b8c9` | Add automation tables | DuplicateTable | | `b7c8d9e0f1a2` | Add last_read_at to chat | DuplicateColumn | | `e1f2a3b4c5d6` | Add is_pinned to note table | DuplicateColumn | | `c1d2e3f4a5b6` | Add shared_chat table and migrate existing shares | UniqueViolation | | `56359461a091` | Add calendar tables | DuplicateTable | ### Complete Workaround & Solution The following steps were required to fully recover from the broken migration state. This is documented here in detail to help other users who encounter the same issue and to provide the maintainers with a clear picture of the impact on end users. #### Step 1: Enter the Docker container ```bash docker exec -it open-webui bash ``` #### Step 2: Export required environment variables The migration scripts require these two environment variables to initialize the application environment. Without them, Alembic will fail with `ValueError: Required environment variable not found`: ```bash export DATABASE_URL="postgresql://user:password@host:5432/dbname" export WEBUI_SECRET_KEY="your_secret_key" cd /app/backend/open_webui ``` #### Step 3: Edit all affected migration files Each migration file needs to be updated to add existence checks before creating or inserting database objects. The files are located at: ``` /app/backend/open_webui/migrations/versions/ ``` The required code changes for each file are as follows: **Fix for table creation (migrations `d4e5f6a7b8c9` and `56359461a091`):** ```python conn = op.get_bind() # Wrap every create_table call with an existence check if not conn.dialect.has_table(conn, 'table_name'): op.create_table('table_name', ...) # Wrap every create_index call with an existence check result = conn.execute(sa.text( "SELECT indexname FROM pg_indexes " "WHERE tablename='table_name' AND indexname='index_name'" )) if result.fetchone() is None: op.create_index('index_name', 'table_name', ['column_name']) ``` **Fix for column addition (migrations `a3dd5bedd151`, `b7c8d9e0f1a2`, `e1f2a3b4c5d6`):** ```python conn = op.get_bind() # Wrap every add_column call with an existence check result = conn.execute(sa.text( "SELECT column_name FROM information_schema.columns " "WHERE table_name='table_name' AND column_name='column_name'" )) if result.fetchone() is None: op.add_column('table_name', sa.Column('column_name', ...)) ``` **Fix for duplicate data inserts (migration `c1d2e3f4a5b6`):** ```python # Before every INSERT into access_grant, check if the record already exists existing_grant = conn.execute( sa.select(access_grant_t.c.id).where( sa.and_( access_grant_t.c.resource_type == 'shared_chat', access_grant_t.c.resource_id == original_chat_id, access_grant_t.c.principal_type == 'user', access_grant_t.c.principal_id == '*', access_grant_t.c.permission == 'read', ) ) ).fetchone() if not existing_grant: conn.execute(access_grant_t.insert().values(...)) # Also check before every INSERT into shared_chat existing_shared = conn.execute( sa.select(shared_chat_t.c.id).where( shared_chat_t.c.id == share_token ) ).fetchone() if not existing_shared: conn.execute(shared_chat_t.insert().values(...)) ``` #### Step 4: Roll back the Alembic stamp to the last known good migration This is necessary to force Alembic to re-execute all the migrations that were partially applied or skipped. The last known good migration before the failures began was `b2c3d4e5f6a7`: ```bash cd /app/backend/open_webui alembic stamp b2c3d4e5f6a7 ``` #### Step 5: Re-run the migrations ```bash alembic upgrade head ``` A successful run should show all 6 migrations completing without errors: ``` INFO [alembic.runtime.migration] Running upgrade b2c3d4e5f6a7 -> a3dd5bedd151, Add tasks and summary columns to chat table INFO [alembic.runtime.migration] Running upgrade a3dd5bedd151 -> d4e5f6a7b8c9, add automation tables INFO [alembic.runtime.migration] Running upgrade d4e5f6a7b8c9 -> b7c8d9e0f1a2, add last_read_at to chat INFO [alembic.runtime.migration] Running upgrade b7c8d9e0f1a2 -> e1f2a3b4c5d6, Add is_pinned to note table INFO [alembic.runtime.migration] Running upgrade e1f2a3b4c5d6 -> c1d2e3f4a5b6, Add shared_chat table and migrate existing shares INFO [alembic.runtime.migration] Running upgrade c1d2e3f4a5b6 -> 56359461a091, add calendar tables ``` #### Step 6: Restart the container ```bash exit docker restart open-webui docker logs -f open-webui ``` ### Impact Assessment This bug has a significant impact on production deployments: - ❌ **Application becomes completely unusable** after pulling the latest image - ❌ **Existing chats are inaccessible** due to failed SQL transactions - ❌ **New messages cannot be sent** due to missing columns - ❌ **Automation features fail** due to missing tables - ❌ **Recovery requires deep technical knowledge** of Docker, PostgreSQL, SQLAlchemy and Alembic - not suitable for non-technical users - ❌ **Risk of data loss** if users attempt a database downgrade without fully understanding the consequences - ✅ **No data was lost** in this specific case after applying the manual fix ### Recommendation In addition to fixing the individual migration scripts, we recommend considering the following improvements to make the migration system more robust: 1. **Add existence checks to all future migration scripts** as a standard practice 2. **Add a pre-migration validation step** that checks the current state of the database before running migrations and warns the user if inconsistencies are found 3. **Improve error messages** to guide users through recovery steps when a migration fails 4. **Add migration rollback handling** so that if a migration fails midway, the database is automatically restored to its previous consistent state 5. **Add integration tests** that simulate partial migration failures to catch these issues before release
GiteaMirror added the bug label 2026-05-15 16:13:55 -05:00
Author
Owner

@bitsofinfo commented on GitHub (Apr 27, 2026):

same get this upgrading from 0.8.10 to 0.9.2

<!-- gh-comment-id:4329027853 --> @bitsofinfo commented on GitHub (Apr 27, 2026): same get this upgrading from 0.8.10 to 0.9.2
Author
Owner

@AndreasUpb commented on GitHub (Apr 28, 2026):

Thanks for writing fail-safe migrations. @juanpabloequihua
Is it fine to ask you for a PR? Our setup only broke on c1d2e3f4a5b6 - Included the patch as described helped a lot to get it working back

/app/backend/open_webui/migrations/versions/c1d2e3f4a5b6_add_shared_chat_table.py

        if not original:
            continue

#------- PATCH
        # Also check before every INSERT into shared_chat
        existing_shared = conn.execute(
            sa.select(shared_chat_t.c.id).where(
                shared_chat_t.c.id == share_token
            )
        ).fetchone()

        if not existing_shared:
            # Insert snapshot into shared_chat
            conn.execute(
                shared_chat_t.insert().values(
                    id=share_token,
                    chat_id=original_chat_id,
                    user_id=original.user_id,
                    title=row.title,
                    chat=row.chat,
                    created_at=row.created_at,
                    updated_at=row.updated_at,
                )
            )

        # Create user:*:read grant for backward compat
        # Before every INSERT into access_grant, check if the record already exists
        existing_grant = conn.execute(
            sa.select(access_grant_t.c.id).where(
                sa.and_(
                    access_grant_t.c.resource_type == 'shared_chat',
                    access_grant_t.c.resource_id == original_chat_id,
                    access_grant_t.c.principal_type == 'user',
                    access_grant_t.c.principal_id == '*',
                    access_grant_t.c.permission == 'read',
                )
            )
        ).fetchone()

        if not existing_grant:
            conn.execute(
                access_grant_t.insert().values(
                    id=str(uuid.uuid4()),
                    resource_type='shared_chat',
                    resource_id=original_chat_id,
                    principal_type='user',
                    principal_id='*',
                    permission='read',
                    created_at=row.created_at or int(time.time()),
                )
            )
#------- ENDPATCH

    # 3. Clean up old phantom rows
<!-- gh-comment-id:4336493071 --> @AndreasUpb commented on GitHub (Apr 28, 2026): Thanks for writing fail-safe migrations. @juanpabloequihua Is it fine to ask you for a PR? Our setup only broke on c1d2e3f4a5b6 - Included the patch as described helped a lot to get it working back /app/backend/open_webui/migrations/versions/c1d2e3f4a5b6_add_shared_chat_table.py ```python if not original: continue #------- PATCH # Also check before every INSERT into shared_chat existing_shared = conn.execute( sa.select(shared_chat_t.c.id).where( shared_chat_t.c.id == share_token ) ).fetchone() if not existing_shared: # Insert snapshot into shared_chat conn.execute( shared_chat_t.insert().values( id=share_token, chat_id=original_chat_id, user_id=original.user_id, title=row.title, chat=row.chat, created_at=row.created_at, updated_at=row.updated_at, ) ) # Create user:*:read grant for backward compat # Before every INSERT into access_grant, check if the record already exists existing_grant = conn.execute( sa.select(access_grant_t.c.id).where( sa.and_( access_grant_t.c.resource_type == 'shared_chat', access_grant_t.c.resource_id == original_chat_id, access_grant_t.c.principal_type == 'user', access_grant_t.c.principal_id == '*', access_grant_t.c.permission == 'read', ) ) ).fetchone() if not existing_grant: conn.execute( access_grant_t.insert().values( id=str(uuid.uuid4()), resource_type='shared_chat', resource_id=original_chat_id, principal_type='user', principal_id='*', permission='read', created_at=row.created_at or int(time.time()), ) ) #------- ENDPATCH # 3. Clean up old phantom rows ```
Author
Owner

@juanpabloequihua commented on GitHub (Apr 28, 2026):

@AndreasUpb no problem, I have submitted the PR to resolve this: #24197

The PR adds idempotency (existence checks) to the 6 affected migration files mentioned in this issue. I have manually verified that these changes allow the migrations to complete successfully on a large PostgreSQL database after the failed migrations.

For reference, here is the log output of the successful migration after applying these changes to my large PostgreSQL instance:

INFO [alembic.runtime.migration] Running upgrade b2c3d4e5f6a7 -> a3dd5bedd151, Add tasks and summary columns to chat table
INFO [alembic.runtime.migration] Running upgrade a3dd5bedd151 -> d4e5f6a7b8c9, add automation tables
INFO [alembic.runtime.migration] Running upgrade d4e5f6a7b8c9 -> b7c8d9e0f1a2, add last_read_at to chat
INFO [alembic.runtime.migration] Running upgrade b7c8d9e0f1a2 -> e1f2a3b4c5d6, Add is_pinned to note table
INFO [alembic.runtime.migration] Running upgrade e1f2a3b4c5d6 -> c1d2e3f4a5b6, Add shared_chat table and migrate existing shares
INFO [alembic.runtime.migration] Running upgrade c1d2e3f4a5b6 -> 56359461a091, add calendar tables
<!-- gh-comment-id:4337845715 --> @juanpabloequihua commented on GitHub (Apr 28, 2026): @AndreasUpb no problem, I have submitted the PR to resolve this: #24197 The PR adds idempotency (existence checks) to the 6 affected migration files mentioned in this issue. I have manually verified that these changes allow the migrations to complete successfully on a large PostgreSQL database after the failed migrations. For reference, here is the log output of the successful migration after applying these changes to my large PostgreSQL instance: > ``` > INFO [alembic.runtime.migration] Running upgrade b2c3d4e5f6a7 -> a3dd5bedd151, Add tasks and summary columns to chat table > INFO [alembic.runtime.migration] Running upgrade a3dd5bedd151 -> d4e5f6a7b8c9, add automation tables > INFO [alembic.runtime.migration] Running upgrade d4e5f6a7b8c9 -> b7c8d9e0f1a2, add last_read_at to chat > INFO [alembic.runtime.migration] Running upgrade b7c8d9e0f1a2 -> e1f2a3b4c5d6, Add is_pinned to note table > INFO [alembic.runtime.migration] Running upgrade e1f2a3b4c5d6 -> c1d2e3f4a5b6, Add shared_chat table and migrate existing shares > INFO [alembic.runtime.migration] Running upgrade c1d2e3f4a5b6 -> 56359461a091, add calendar tables > ```
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/open-webui#90937