issues upgrading schema form 3.8 to 3.9

Hello privacyidea community!

I have been tasked upgrading my companies privacyidea which has been abandoned for some time. I started at 3.5 and worked my way up to 3.8 but now I’ve het a wall with 3.9.

My dev environment is currently running on Alma Linux 9, python 3.9 with postgres Engine 16 for the database. The database and privacyidea configuration are imported from production which started at privacyidea 3.5. I’ve got a database backup for every version.

Installing the application via pip has shown no issues but the schema upgrade fails with the following message:

Running online
CurrentID in Table authcache: 1
 +++ Creating Sequence: authcache_seq
CurrentID in Table caconnector: 1
 +++ Creating Sequence: caconnector_seq
Traceback (most recent call last):
  File "/opt/privacyidea/lib64/python3.9/site-packages/sqlalchemy/engine/base.py", line 1900, in _execute_context
    self.dialect.do_execute(
  File "/opt/privacyidea/lib64/python3.9/site-packages/sqlalchemy/engine/default.py", line 736, in do_execute
    cursor.execute(statement, parameters)
psycopg2.errors.InFailedSqlTransaction: current transaction is aborted, commands ignored until end of transaction block

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/opt/privacyidea/bin/pi-manage", line 1739, in <module>
    manager.run()
  File "/opt/privacyidea/lib/python3.9/site-packages/flask_script/__init__.py", line 417, in run
    result = self.handle(argv[0], argv[1:])
  File "/opt/privacyidea/lib/python3.9/site-packages/flask_script/__init__.py", line 386, in handle
    res = handle(*args, **config)
  File "/opt/privacyidea/lib/python3.9/site-packages/flask_script/commands.py", line 216, in __call__
    return self.run(*args, **kwargs)
  File "/opt/privacyidea/lib/python3.9/site-packages/flask_migrate/__init__.py", line 96, in wrapped
    f(*args, **kwargs)
  File "/opt/privacyidea/lib/python3.9/site-packages/flask_migrate/__init__.py", line 271, in upgrade
    command.upgrade(config, revision, sql=sql, tag=tag)
  File "/opt/privacyidea/lib/python3.9/site-packages/alembic/command.py", line 378, in upgrade
    script.run_env()
  File "/opt/privacyidea/lib/python3.9/site-packages/alembic/script/base.py", line 576, in run_env
    util.load_python_file(self.dir, "env.py")
  File "/opt/privacyidea/lib/python3.9/site-packages/alembic/util/pyfiles.py", line 94, in load_python_file
    module = load_module_py(module_id, path)
  File "/opt/privacyidea/lib/python3.9/site-packages/alembic/util/pyfiles.py", line 110, in load_module_py
    spec.loader.exec_module(module)  # type: ignore
  File "<frozen importlib._bootstrap_external>", line 850, in exec_module
  File "<frozen importlib._bootstrap>", line 228, in _call_with_frames_removed
  File "/opt/privacyidea/lib/privacyidea/migrations/env.py", line 110, in <module>
    run_migrations_online()
  File "/opt/privacyidea/lib/privacyidea/migrations/env.py", line 100, in run_migrations_online
    context.run_migrations()
  File "<string>", line 8, in run_migrations
  File "/opt/privacyidea/lib/python3.9/site-packages/alembic/runtime/environment.py", line 867, in run_migrations
    self.get_context().run_migrations(**kw)
  File "/opt/privacyidea/lib/python3.9/site-packages/alembic/runtime/migration.py", line 624, in run_migrations
    step.migration_fn(**kw)
  File "/opt/privacyidea/lib/privacyidea/migrations/versions/5cb310101a1f_.py", line 51, in upgrade
    current_id = session.query(func.max(tbl.c.id)).one()[0] or 1
  File "/opt/privacyidea/lib64/python3.9/site-packages/sqlalchemy/orm/query.py", line 2870, in one
    return self._iter().one()
  File "/opt/privacyidea/lib64/python3.9/site-packages/sqlalchemy/orm/query.py", line 2916, in _iter
    result = self.session.execute(
  File "/opt/privacyidea/lib64/python3.9/site-packages/sqlalchemy/orm/session.py", line 1714, in execute
    result = conn._execute_20(statement, params or {}, execution_options)
  File "/opt/privacyidea/lib64/python3.9/site-packages/sqlalchemy/engine/base.py", line 1705, in _execute_20
    return meth(self, args_10style, kwargs_10style, execution_options)
  File "/opt/privacyidea/lib64/python3.9/site-packages/sqlalchemy/sql/elements.py", line 334, in _execute_on_connection
    return connection._execute_clauseelement(
  File "/opt/privacyidea/lib64/python3.9/site-packages/sqlalchemy/engine/base.py", line 1572, in _execute_clauseelement
    ret = self._execute_context(
  File "/opt/privacyidea/lib64/python3.9/site-packages/sqlalchemy/engine/base.py", line 1943, in _execute_context
    self._handle_dbapi_exception(
  File "/opt/privacyidea/lib64/python3.9/site-packages/sqlalchemy/engine/base.py", line 2124, in _handle_dbapi_exception
    util.raise_(
  File "/opt/privacyidea/lib64/python3.9/site-packages/sqlalchemy/util/compat.py", line 211, in raise_
    raise exception
  File "/opt/privacyidea/lib64/python3.9/site-packages/sqlalchemy/engine/base.py", line 1900, in _execute_context
    self.dialect.do_execute(
  File "/opt/privacyidea/lib64/python3.9/site-packages/sqlalchemy/engine/default.py", line 736, in do_execute
    cursor.execute(statement, parameters)
sqlalchemy.exc.InternalError: (psycopg2.errors.InFailedSqlTransaction) current transaction is aborted, commands ignored until end of transaction block

[SQL: SELECT max(challenge.id) AS max_1 
FROM challenge]
(Background on this error at: https://sqlalche.me/e/14/2j85)

The assumption is that the schema upgrade fails at the query SELECT max(challenge.id) AS max_1 FROM challenge. When running the query manually I get the following result:

FROM challenge;
 max_1 
-------
      
(1 row)

When doing a simple select * from challenge; It returns an empty table. So I am not surprised by this result.

The command used to initiate the schema upgrade is:
privacyidea-schema-upgrade /opt/privacyidea/lib/privacyidea/migrations

I am at a loss on what is going wrong here and what I can do to resolve this. Any suggestions on how to troubleshoot this are welcome.

Hm, I think none should usually be interpreted as 0.

If this is you assumption, you could easily trick the migration script and simply insert a bogus challenge.

Hello Cornelinux,

Thanks for taking the time to respond. I’ve tried manually adding an entry via the query:

INSERT INTO challenge (
    id, transaction_id, data, challenge, session, serial, timestamp, expiration, received_count, otp_valid
) VALUES (
    1, 'trans123', 'sample data', 'sample challenge', 'sample session', 'serial123', '2025-01-27 11:00:00', '2025-01-28 11:00:00', 0, false
);

Now I get the result:

FROM challenge;
 max_1 
-------
     1
(1 row)

However I still get the same error when running the schema upgrade.
Currently my database is at revision d5870fd2f2a4. Privacyidea 3.5, upgrading to 3.9.

When upgrading to every version step by step I get up to revision 006d4747f858, Privacyidea 3.8, here the error is also present.

privacyIDEA uses alembic for database schema versioning.

You can use

pi-manage db history -d /opt/privacyidea/lib/privacyidea/migrations/

to see all database versions.

This way you can look a bit more into detail, where things will break.
Are you actually running an installation via pip?

I am also not sure, if there might be problems with specific DB versions.

So you get till this version:

d3c0f0403a84 -> 006d4747f858, v3.8: Add thread_id to audit_log

Version 3.9 has these two DB migrations:

4a0aec37e7cf -> 5cb310101a1f, v3.9: Create sequences needed for SQLAlchemy 1.4
006d4747f858 -> 4a0aec37e7cf, v3.9: Add table serviceid

You are faling at the 2nd one.

“5cb310101a1f” actually corresponds to a migration script in

/opt/privacyidea/lib/privacyidea/migrations/versions/5cb310101a1f_.py

(Just as some background information)

Did you actually ever used privacyIDEA with challenge response? I assume this table was never used?

Yes I am installing through pip, the requirements get installed through the requirements.txt in the Github repository corresponding to the Privacyidea version. Privacyidea itself is installed with

pip install -upgrade privacyidea==3.9

for example,

All our users use TOTP tokens to authenticate.

I used AI to translate the migration scripts to SQL and got the following:

DO $ 
DECLARE
    tbl RECORD;
    current_id INTEGER;
BEGIN
    -- Loop over all tables defined in the current models.py
    FOR tbl IN 
        SELECT table_name 
        FROM information_schema.tables 
        WHERE table_schema = 'public' 
    LOOP
        -- Check if the table has an "id" column
        IF EXISTS (
            SELECT 1 
            FROM information_schema.columns 
            WHERE table_name = tbl.table_name 
            AND column_name = 'id'
        ) THEN
            -- Get the current maximum id value
            EXECUTE format('SELECT COALESCE(MAX(id), 0) FROM %I', tbl.table_name) INTO current_id;
            
            -- Create the sequence with the correct next_id
            BEGIN
                EXECUTE format('CREATE SEQUENCE IF NOT EXISTS %I_seq START %s', tbl.table_name, current_id + 1);
            EXCEPTION
                WHEN duplicate_table THEN
                    -- Sequence already exists, skip creation
                    RAISE NOTICE 'Sequence % already exists, skipping', tbl.table_name || '_seq';
            END;
            
            -- Set the default value of the id column to use the sequence
            EXECUTE format('ALTER TABLE %I ALTER COLUMN id SET DEFAULT nextval(%L)', tbl.table_name, tbl.table_name || '_seq');
        END IF;
    END LOOP;
END $;

Currently I am getting the following output:

NOTICE:  relation "challenge_seq" already exists, skipping
NOTICE:  relation "eventhandler_seq" already exists, skipping
NOTICE:  relation "eventhandlercondition_seq" already exists, skipping
NOTICE:  relation "clientapplication_seq" already exists, skipping
NOTICE:  relation "eventcounter_seq" already exists, skipping
NOTICE:  relation "authcache_seq" already exists, skipping
NOTICE:  relation "caconnector_seq" already exists, skipping
NOTICE:  relation "caconnectorconfig_seq" already exists, skipping
NOTICE:  relation "machineresolver_seq" already exists, skipping
NOTICE:  relation "machinetoken_seq" already exists, skipping
NOTICE:  relation "machinetokenoptions_seq" already exists, skipping
NOTICE:  relation "monitoringstats_seq" already exists, skipping
NOTICE:  relation "eventhandleroption_seq" already exists, skipping
NOTICE:  relation "passwordreset_seq" already exists, skipping
NOTICE:  relation "periodictaskoption_seq" already exists, skipping
NOTICE:  relation "policy_seq" already exists, skipping
NOTICE:  relation "policycondition_seq" already exists, skipping
NOTICE:  relation "realm_seq" already exists, skipping
NOTICE:  relation "periodictask_seq" already exists, skipping
NOTICE:  relation "privacyideaserver_seq" already exists, skipping
NOTICE:  relation "radiusserver_seq" already exists, skipping
NOTICE:  relation "pidea_audit_seq" already exists, skipping
NOTICE:  relation "resolverrealm_seq" already exists, skipping
NOTICE:  relation "smsgateway_seq" already exists, skipping
NOTICE:  relation "smsgatewayoption_seq" already exists, skipping
NOTICE:  relation "smtpserver_seq" already exists, skipping
NOTICE:  relation "subscription_seq" already exists, skipping
NOTICE:  relation "resolver_seq" already exists, skipping
NOTICE:  relation "resolverconfig_seq" already exists, skipping
NOTICE:  relation "token_seq" already exists, skipping
NOTICE:  relation "tokenowner_seq" already exists, skipping
NOTICE:  relation "tokenrealm_seq" already exists, skipping
NOTICE:  relation "usercache_seq" already exists, skipping
NOTICE:  relation "machineresolverconfig_seq" already exists, skipping
NOTICE:  relation "periodictasklastrun_seq" already exists, skipping
NOTICE:  relation "tokeninfo_seq" already exists, skipping
NOTICE:  relation "customuserattribute_seq" already exists, skipping
NOTICE:  relation "tokentokengroup_seq" already exists, skipping
NOTICE:  relation "tokengroup_seq" already exists, skipping
NOTICE:  relation "serviceid_seq" already exists, skipping
DO

Now I am getting the same error on a different table, caconnector:

(privacyidea) bash-5.1$ privacyidea-schema-upgrade /opt/privacyidea/lib/privacyidea/migrations

             _                    _______  _______
   ___  ____(_)  _____ _______ __/  _/ _ \/ __/ _ |
  / _ \/ __/ / |/ / _ `/ __/ // // // // / _// __ |
 / .__/_/ /_/|___/\_,_/\__/\_, /___/____/___/_/ |_|
/_/                       /___/
                                               v3.9
    
++ Upgrading DB schema.
[2025-01-28 11:19:50,029][303145][140264100800320][DEBUG][privacyidea.app:233] Reading application from the static folder /opt/privacyidea/lib/python3.9/site-packages/privacyidea/static and the template folder static/templates/
[2025-01-28 11:19:50,029][303145][140264100800320][DEBUG][privacyidea.app:233] Reading application from the static folder /opt/privacyidea/lib/python3.9/site-packages/privacyidea/static and the template folder static/templates/

             _                    _______  _______
   ___  ____(_)  _____ _______ __/  _/ _ \/ __/ _ |
  / _ \/ __/ / |/ / _ `/ __/ // // // // / _// __ |
 / .__/_/ /_/|___/\_,_/\__/\_, /___/____/___/_/ |_|
/_/                       /___/
                                               v3.9
    
Running online
CurrentID in Table authcache: 1
 +++ Creating Sequence: authcache_seq
Traceback (most recent call last):
  File "/opt/privacyidea/lib64/python3.9/site-packages/sqlalchemy/engine/base.py", line 1910, in _execute_context
    self.dialect.do_execute(
  File "/opt/privacyidea/lib64/python3.9/site-packages/sqlalchemy/engine/default.py", line 736, in do_execute
    cursor.execute(statement, parameters)
psycopg2.errors.InFailedSqlTransaction: current transaction is aborted, commands ignored until end of transaction block


The above exception was the direct cause of the following exception:



Traceback (most recent call last):
  File "/opt/privacyidea/bin/pi-manage", line 1739, in <module>
    manager.run()
  File "/opt/privacyidea/lib/python3.9/site-packages/flask_script/__init__.py", line 417, in run
    result = self.handle(argv[0], argv[1:])
  File "/opt/privacyidea/lib/python3.9/site-packages/flask_script/__init__.py", line 386, in handle
    res = handle(*args, **config)
  File "/opt/privacyidea/lib/python3.9/site-packages/flask_script/commands.py", line 216, in __call__
    return self.run(*args, **kwargs)
  File "/opt/privacyidea/lib/python3.9/site-packages/flask_migrate/__init__.py", line 96, in wrapped
    f(*args, **kwargs)
  File "/opt/privacyidea/lib/python3.9/site-packages/flask_migrate/__init__.py", line 271, in upgrade
    command.upgrade(config, revision, sql=sql, tag=tag)
  File "/opt/privacyidea/lib/python3.9/site-packages/alembic/command.py", line 378, in upgrade
    script.run_env()
  File "/opt/privacyidea/lib/python3.9/site-packages/alembic/script/base.py", line 576, in run_env
    util.load_python_file(self.dir, "env.py")
  File "/opt/privacyidea/lib/python3.9/site-packages/alembic/util/pyfiles.py", line 94, in load_python_file
    module = load_module_py(module_id, path)
  File "/opt/privacyidea/lib/python3.9/site-packages/alembic/util/pyfiles.py", line 110, in load_module_py
    spec.loader.exec_module(module)  # type: ignore
  File "<frozen importlib._bootstrap_external>", line 850, in exec_module
  File "<frozen importlib._bootstrap>", line 228, in _call_with_frames_removed
  File "/opt/privacyidea/lib/privacyidea/migrations/env.py", line 110, in <module>
    run_migrations_online()
  File "/opt/privacyidea/lib/privacyidea/migrations/env.py", line 100, in run_migrations_online
    context.run_migrations()
  File "<string>", line 8, in run_migrations
  File "/opt/privacyidea/lib/python3.9/site-packages/alembic/runtime/environment.py", line 867, in run_migrations
    self.get_context().run_migrations(**kw)
  File "/opt/privacyidea/lib/python3.9/site-packages/alembic/runtime/migration.py", line 624, in run_migrations
    step.migration_fn(**kw)
  File "/opt/privacyidea/lib/privacyidea/migrations/versions/5cb310101a1f_.py", line 51, in upgrade
    current_id = session.query(func.max(tbl.c.id)).one()[0] or 1
  File "/opt/privacyidea/lib64/python3.9/site-packages/sqlalchemy/orm/query.py", line 2870, in one
    return self._iter().one()
  File "/opt/privacyidea/lib64/python3.9/site-packages/sqlalchemy/orm/query.py", line 2916, in _iter
    result = self.session.execute(
  File "/opt/privacyidea/lib64/python3.9/site-packages/sqlalchemy/orm/session.py", line 1717, in execute
    result = conn._execute_20(statement, params or {}, execution_options)
  File "/opt/privacyidea/lib64/python3.9/site-packages/sqlalchemy/engine/base.py", line 1710, in _execute_20
    return meth(self, args_10style, kwargs_10style, execution_options)
  File "/opt/privacyidea/lib64/python3.9/site-packages/sqlalchemy/sql/elements.py", line 334, in _execute_on_connection
    return connection._execute_clauseelement(
  File "/opt/privacyidea/lib64/python3.9/site-packages/sqlalchemy/engine/base.py", line 1577, in _execute_clauseelement
    ret = self._execute_context(
  File "/opt/privacyidea/lib64/python3.9/site-packages/sqlalchemy/engine/base.py", line 1953, in _execute_context
    self._handle_dbapi_exception(
  File "/opt/privacyidea/lib64/python3.9/site-packages/sqlalchemy/engine/base.py", line 2134, in _handle_dbapi_exception
    util.raise_(
  File "/opt/privacyidea/lib64/python3.9/site-packages/sqlalchemy/util/compat.py", line 211, in raise_
    raise exception
  File "/opt/privacyidea/lib64/python3.9/site-packages/sqlalchemy/engine/base.py", line 1910, in _execute_context
    self.dialect.do_execute(
  File "/opt/privacyidea/lib64/python3.9/site-packages/sqlalchemy/engine/default.py", line 736, in do_execute
    cursor.execute(statement, parameters)
sqlalchemy.exc.InternalError: (psycopg2.errors.InFailedSqlTransaction) current transaction is aborted, commands ignored until end of transaction block

[SQL: SELECT max(caconnector.id) AS max_1 
FROM caconnector]
(Background on this error at: https://sqlalche.me/e/14/2j85)

The fact its failing over a different table now confuses me to no end. The scripts generated by AI Didn’t do anything in particular with the challenge table. I’d love to know what causes it to succeed this time around.

The AI translated query appears to be working just fine.

I’m also got same issues with upgrading schema. Debian 11, Postgres;

Upgrade fails, because it looks like the migration scripts don’t handle “already existing” tables/sequences correctly. So committing transaction fails.

++ Upgrading DB schema.

             _                    _______  _______
   ___  ____(_)  _____ _______ __/  _/ _ \/ __/ _ |
  / _ \/ __/ / |/ / _ `/ __/ // // // // / _// __ |
 / .__/_/ /_/|___/\_,_/\__/\_, /___/____/___/_/ |_|
/_/                       /___/
                                            v3.10.2

Running online
CurrentID in Table authcache: 0
 +++ Creating Sequence: authcache_seq
CurrentID in Table caconnector: 0
 +++ Creating Sequence: caconnector_seq
Traceback (most recent call last):
  File "/opt/privacyidea/lib/python3.9/site-packages/sqlalchemy/engine/base.py", line 1910, in _execute_context
    self.dialect.do_execute(
  File "/opt/privacyidea/lib/python3.9/site-packages/sqlalchemy/engine/default.py", line 736, in do_execute
    cursor.execute(statement, parameters)
psycopg2.errors.DuplicateTable: FEHLER:  Relation »caconnector_seq« existiert bereits


The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/opt/privacyidea/bin/pi-manage", line 8, in <module>
    sys.exit(cli())
  File "/opt/privacyidea/lib/python3.9/site-packages/click/core.py", line 829, in __call__
    return self.main(*args, **kwargs)
  File "/opt/privacyidea/lib/python3.9/site-packages/flask/cli.py", line 586, in main
    return super(FlaskGroup, self).main(*args, **kwargs)
  File "/opt/privacyidea/lib/python3.9/site-packages/click/core.py", line 782, in main
    rv = self.invoke(ctx)
  File "/opt/privacyidea/lib/python3.9/site-packages/click/core.py", line 1259, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
  File "/opt/privacyidea/lib/python3.9/site-packages/click/core.py", line 1259, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
  File "/opt/privacyidea/lib/python3.9/site-packages/click/core.py", line 1066, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "/opt/privacyidea/lib/python3.9/site-packages/click/core.py", line 610, in invoke
    return callback(*args, **kwargs)
  File "/opt/privacyidea/lib/python3.9/site-packages/click/decorators.py", line 21, in new_func
    return f(get_current_context(), *args, **kwargs)
  File "/opt/privacyidea/lib/python3.9/site-packages/flask/cli.py", line 426, in decorator
    return __ctx.invoke(f, *args, **kwargs)
  File "/opt/privacyidea/lib/python3.9/site-packages/click/core.py", line 610, in invoke
    return callback(*args, **kwargs)
  File "/opt/privacyidea/lib/python3.9/site-packages/flask_migrate/cli.py", line 136, in upgrade
    _upgrade(directory, revision, sql, tag, x_arg)
  File "/opt/privacyidea/lib/python3.9/site-packages/flask_migrate/__init__.py", line 96, in wrapped
    f(*args, **kwargs)
  File "/opt/privacyidea/lib/python3.9/site-packages/flask_migrate/__init__.py", line 271, in upgrade
    command.upgrade(config, revision, sql=sql, tag=tag)
  File "/opt/privacyidea/lib/python3.9/site-packages/alembic/command.py", line 406, in upgrade
    script.run_env()
  File "/opt/privacyidea/lib/python3.9/site-packages/alembic/script/base.py", line 586, in run_env
    util.load_python_file(self.dir, "env.py")
  File "/opt/privacyidea/lib/python3.9/site-packages/alembic/util/pyfiles.py", line 95, in load_python_file
    module = load_module_py(module_id, path)
  File "/opt/privacyidea/lib/python3.9/site-packages/alembic/util/pyfiles.py", line 113, in load_module_py
    spec.loader.exec_module(module)  # type: ignore
  File "<frozen importlib._bootstrap_external>", line 790, in exec_module
  File "<frozen importlib._bootstrap>", line 228, in _call_with_frames_removed
  File "/opt/privacyidea/lib/privacyidea/migrations/env.py", line 111, in <module>
    run_migrations_online()
  File "/opt/privacyidea/lib/privacyidea/migrations/env.py", line 101, in run_migrations_online
    context.run_migrations()
  File "<string>", line 8, in run_migrations
  File "/opt/privacyidea/lib/python3.9/site-packages/alembic/runtime/environment.py", line 946, in run_migrations
    self.get_context().run_migrations(**kw)
  File "/opt/privacyidea/lib/python3.9/site-packages/alembic/runtime/migration.py", line 628, in run_migrations
    step.migration_fn(**kw)
  File "/opt/privacyidea/lib/privacyidea/migrations/versions/5cb310101a1f_.py", line 56, in upgrade
    op.execute(CreateSequence(seq, if_not_exists=True))
  File "<string>", line 8, in execute
  File "<string>", line 3, in execute
  File "/opt/privacyidea/lib/python3.9/site-packages/alembic/operations/ops.py", line 2551, in execute
    return operations.invoke(op)
  File "/opt/privacyidea/lib/python3.9/site-packages/alembic/operations/base.py", line 442, in invoke
    return fn(self, operation)
  File "/opt/privacyidea/lib/python3.9/site-packages/alembic/operations/toimpl.py", line 236, in execute_sql
    operations.migration_context.impl.execute(
  File "/opt/privacyidea/lib/python3.9/site-packages/alembic/ddl/impl.py", line 217, in execute
    self._exec(sql, execution_options)
  File "/opt/privacyidea/lib/python3.9/site-packages/alembic/ddl/impl.py", line 210, in _exec
    return conn.execute(construct, params)
  File "/opt/privacyidea/lib/python3.9/site-packages/sqlalchemy/engine/base.py", line 1385, in execute
    return meth(self, multiparams, params, _EMPTY_EXECUTION_OPTS)
  File "/opt/privacyidea/lib/python3.9/site-packages/sqlalchemy/sql/ddl.py", line 80, in _execute_on_connection
    return connection._execute_ddl(
  File "/opt/privacyidea/lib/python3.9/site-packages/sqlalchemy/engine/base.py", line 1477, in _execute_ddl
    ret = self._execute_context(
  File "/opt/privacyidea/lib/python3.9/site-packages/sqlalchemy/engine/base.py", line 1953, in _execute_context
    self._handle_dbapi_exception(
  File "/opt/privacyidea/lib/python3.9/site-packages/sqlalchemy/engine/base.py", line 2134, in _handle_dbapi_exception
    util.raise_(
  File "/opt/privacyidea/lib/python3.9/site-packages/sqlalchemy/util/compat.py", line 211, in raise_
    raise exception
  File "/opt/privacyidea/lib/python3.9/site-packages/sqlalchemy/engine/base.py", line 1910, in _execute_context
    self.dialect.do_execute(
  File "/opt/privacyidea/lib/python3.9/site-packages/sqlalchemy/engine/default.py", line 736, in do_execute
    cursor.execute(statement, parameters)
sqlalchemy.exc.ProgrammingError: (psycopg2.errors.DuplicateTable) FEHLER:  Relation »caconnector_seq« existiert bereits

[SQL: CREATE SEQUENCE caconnector_seq START WITH 1]
(Background on this error at: https://sqlalche.me/e/14/f405)

migration 5cb310101a1f_.py seems to be the culprit - at least according to the error message

It looks like there is an error in a loop and Postgres does not close the transaction. So the next round, the transaction is still active and the error occurs during the SELECT max() statement.
As @Killom mentioned, the migration file 5cb310101a1f_.py adds a bunch of sequences to the database when they are missing.
Since Postgres is using sequences by default, they should not be added here.
I’ll try to reproduce this to figure out how we can avoid this.
@Pieter-Visscher after running the SQL-Script You should stamp the database to the version as if the script ran successfully (like pi-manage db stamp 5cb310101a1f -d /opt/privacyidea/lib/privacyidea/migrations ).

Thats it! I have managed to upgrade my schema to 69e7817b9863 in the development environment. I still have to upgrade the production environment. Do you have a timeline in mind for when a possible fix will be released? If not that is no problem, then I will refine the upgrade procedure with the current work around.

@plettich Had similar issues back some time ago; So it might be a good idea to also revisit the older migrations.