Skip to content

outposts: update permissions more eagerly (cherry-pick #17783 to version-2025.10)#17841

Merged
BeryJu merged 1 commit intoversion-2025.10from
cherry-pick/17783-to-version-2025.10
Oct 30, 2025
Merged

outposts: update permissions more eagerly (cherry-pick #17783 to version-2025.10)#17841
BeryJu merged 1 commit intoversion-2025.10from
cherry-pick/17783-to-version-2025.10

Conversation

@authentik-automation
Copy link
Contributor

Cherry-pick of #17783 to version-2025.10 branch.

Original PR: #17783
Original Author: @dominic-r
Cherry-picked commit: ec00a91

* wip

* wip

* a

* a

Signed-off-by: Dominic R <dominic@sdko.org>

* rm

* this

* rm test files

* cover one more case

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

---------

Signed-off-by: Dominic R <dominic@sdko.org>
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
Co-authored-by: Jens Langhammer <jens@goauthentik.io>
@netlify
Copy link

netlify bot commented Oct 30, 2025

Deploy Preview for authentik-integrations ready!

Name Link
🔨 Latest commit e7c196d
🔍 Latest deploy log https://app.netlify.com/projects/authentik-integrations/deploys/6903a1a8d393370008a48693
😎 Deploy Preview https://deploy-preview-17841--authentik-integrations.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@netlify
Copy link

netlify bot commented Oct 30, 2025

Deploy Preview for authentik-docs canceled.

Name Link
🔨 Latest commit e7c196d
🔍 Latest deploy log https://app.netlify.com/projects/authentik-docs/deploys/6903a1a8b8caa8000920cbbe

@BeryJu BeryJu added this to the Release 2025.10.1 milestone Oct 30, 2025
@codecov
Copy link

codecov bot commented Oct 30, 2025

❌ 6 Tests Failed:

Tests completed Failed Passed Skipped
2195 6 2189 2
View the top 3 failed test(s) by shortest run time
authentik.tenants.tests.test_recovery.TestRecovery::test_recovery_admin_group_invalid
Stack Traces | 11.9s run time
self = <DatabaseWrapper vendor='postgresql' alias='default'>

    def _commit(self):
        if self.connection is not None:
            with debug_transaction(self, "COMMIT"), self.wrap_database_errors:
>               return self.connection.commit()

.venv/lib/python3.13.../backends/base/base.py:303: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <psycopg.Connection [BAD] at 0x7f47dc9da6c0>

    def commit(self) -> None:
        """Commit any pending transaction to the database."""
        with self.lock:
>           self.wait(self._commit_gen())

.venv/lib/python3.13............/site-packages/psycopg/connection.py:262: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <psycopg.Connection [BAD] at 0x7f47dc9da6c0>
gen = <generator object BaseConnection._commit_gen at 0x7f47dfe0de40>
interval = 0.1

    def wait(self, gen: PQGen[RV], interval: float | None = _WAIT_INTERVAL) -> RV:
        """
        Consume a generator operating on the connection.
    
        The function must be used on generators that don't change connection
        fd (i.e. not on connect and reset).
        """
        try:
>           return waiting.wait(gen, self.pgconn.socket, interval=interval)

.venv/lib/python3.13............/site-packages/psycopg/connection.py:414: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

>   ???

psycopg_c/_psycopg/waiting.pyx:213: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <psycopg.Connection [BAD] at 0x7f47dc9da6c0>

    def _commit_gen(self) -> PQGen[None]:
        """Generator implementing `Connection.commit()`."""
        if self._num_transactions:
            raise e.ProgrammingError(
                "Explicit commit() forbidden within a Transaction "
                "context. (Transaction will be automatically committed "
                "on successful exit from context.)"
            )
        if self._tpc:
            raise e.ProgrammingError(
                "commit() cannot be used during a two-phase transaction"
            )
        if self.pgconn.transaction_status == IDLE:
            return
    
>       yield from self._exec_command(b"COMMIT")

.venv/lib/python3.13............/site-packages/psycopg/_connection_base.py:580: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <psycopg.Connection [BAD] at 0x7f47dc9da6c0>, command = b'COMMIT'
result_format = <Format.TEXT: 0>

    def _exec_command(
        self, command: Query, result_format: pq.Format = TEXT
    ) -> PQGen[PGresult | None]:
        """
        Generator to send a command and receive the result to the backend.
    
        Only used to implement internal commands such as "commit", with eventual
        arguments bound client-side. The cursor can do more complex stuff.
        """
        self._check_connection_ok()
    
        if isinstance(command, str):
            command = command.encode(self.pgconn._encoding)
        elif isinstance(command, Composable):
            command = command.as_bytes(self)
    
        if self._pipeline:
            cmd = partial(
                self.pgconn.send_query_params,
                command,
                None,
                result_format=result_format,
            )
            self._pipeline.command_queue.append(cmd)
            self._pipeline.result_queue.append(None)
            return None
    
        # Unless needed, use the simple query protocol, e.g. to interact with
        # pgbouncer. In pipeline mode we always use the advanced query protocol
        # instead, see #350
        if result_format == TEXT:
            self.pgconn.send_query(command)
        else:
            self.pgconn.send_query_params(command, None, result_format=result_format)
    
        result: PGresult = (yield from generators.execute(self.pgconn))[-1]
        if result.status != COMMAND_OK and result.status != TUPLES_OK:
            if result.status == FATAL_ERROR:
>               raise e.error_from_result(result, encoding=self.pgconn._encoding)
E               psycopg.errors.ForeignKeyViolation: insert or update on table "authentik_core_token" violates foreign key constraint "authentik_core_token_user_id_479d5b79_fk_authentik_core_user_id"
E               DETAIL:  Key (user_id)=(2) is not present in table "authentik_core_user".

.venv/lib/python3.13............/site-packages/psycopg/_connection_base.py:478: ForeignKeyViolation

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

self = <unittest.case._Outcome object at 0x7f47df75f8c0>
test_case = <authentik.tenants.tests.test_recovery.TestRecovery testMethod=test_recovery_admin_group_invalid>
subTest = False

    @contextlib.contextmanager
    def testPartExecutor(self, test_case, subTest=False):
        old_success = self.success
        self.success = True
        try:
>           yield

.../hostedtoolcache/Python/3.13.7........./x64/lib/python3.13/unittest/case.py:58: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <authentik.tenants.tests.test_recovery.TestRecovery testMethod=test_recovery_admin_group_invalid>
result = <TestCaseFunction test_recovery_admin_group_invalid>

    def run(self, result=None):
        if result is None:
            result = self.defaultTestResult()
            startTestRun = getattr(result, 'startTestRun', None)
            stopTestRun = getattr(result, 'stopTestRun', None)
            if startTestRun is not None:
                startTestRun()
        else:
            stopTestRun = None
    
        result.startTest(self)
        try:
            testMethod = getattr(self, self._testMethodName)
            if (getattr(self.__class__, "__unittest_skip__", False) or
                getattr(testMethod, "__unittest_skip__", False)):
                # If the class or method was skipped.
                skip_why = (getattr(self.__class__, '__unittest_skip_why__', '')
                            or getattr(testMethod, '__unittest_skip_why__', ''))
                _addSkip(result, self, skip_why)
                return result
    
            expecting_failure = (
                getattr(self, "__unittest_expecting_failure__", False) or
                getattr(testMethod, "__unittest_expecting_failure__", False)
            )
            outcome = _Outcome(result)
            start_time = time.perf_counter()
            try:
                self._outcome = outcome
    
                with outcome.testPartExecutor(self):
>                   self._callSetUp()

.../hostedtoolcache/Python/3.13.7........./x64/lib/python3.13/unittest/case.py:647: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <authentik.tenants.tests.test_recovery.TestRecovery testMethod=test_recovery_admin_group_invalid>

    def _callSetUp(self):
>       self.setUp()

.../hostedtoolcache/Python/3.13.7........./x64/lib/python3.13/unittest/case.py:603: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <authentik.tenants.tests.test_recovery.TestRecovery testMethod=test_recovery_admin_group_invalid>

    def setUp(self):
>       super().setUp()

.../tenants/tests/test_recovery.py:22: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <authentik.tenants.tests.test_recovery.TestRecovery testMethod=test_recovery_admin_group_invalid>

    def setUp(self):
        with schema_context(get_public_schema_name()):
>           Tenant.objects.update_or_create(
                defaults={"name": "Template", "ready": False},
                schema_name=get_tenant_base_schema(),
            )

.../tenants/tests/utils.py:24: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <django.db.models.manager.Manager object at 0x7f47e8ac5a50>, args = ()
kwargs = {'defaults': {'name': 'Template', 'ready': False}, 'schema_name': 'template'}

    @wraps(method)
    def manager_method(self, *args, **kwargs):
>       return getattr(self.get_queryset(), name)(*args, **kwargs)

.venv/lib/python3.13.../db/models/manager.py:87: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <QuerySet [<Tenant: Tenant Default>]>
defaults = {'name': 'Template', 'ready': False}
create_defaults = {'name': 'Template', 'ready': False}
kwargs = {'schema_name': 'template'}
update_defaults = {'name': 'Template', 'ready': False}
obj = <Tenant: Tenant Template>, created = True

    def update_or_create(self, defaults=None, create_defaults=None, **kwargs):
        """
        Look up an object with the given kwargs, updating one with defaults
        if it exists, otherwise create a new one. Optionally, an object can
        be created with different values than defaults by using
        create_defaults.
        Return a tuple (object, created), where created is a boolean
        specifying whether an object was created.
        """
        update_defaults = defaults or {}
        if create_defaults is None:
            create_defaults = update_defaults
    
        self._for_write = True
>       with transaction.atomic(using=self.db):

.venv/lib/python3.13.../db/models/query.py:985: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <django.db.transaction.Atomic object at 0x7f47eaa8e350>, exc_type = None
exc_value = None, traceback = None

    def __exit__(self, exc_type, exc_value, traceback):
        connection = get_connection(self.using)
    
        if connection.in_atomic_block:
            connection.atomic_blocks.pop()
    
        if connection.savepoint_ids:
            sid = connection.savepoint_ids.pop()
        else:
            # Prematurely unset this flag to allow using commit or rollback.
            connection.in_atomic_block = False
    
        try:
            if connection.closed_in_transaction:
                # The database will perform a rollback by itself.
                # Wait until we exit the outermost block.
                pass
    
            elif exc_type is None and not connection.needs_rollback:
                if connection.in_atomic_block:
                    # Release savepoint if there is one
                    if sid is not None:
                        try:
                            connection.savepoint_commit(sid)
                        except DatabaseError:
                            try:
                                connection.savepoint_rollback(sid)
                                # The savepoint won't be reused. Release it to
                                # minimize overhead for the database server.
                                connection.savepoint_commit(sid)
                            except Error:
                                # If rolling back to a savepoint fails, mark for
                                # rollback at a higher level and avoid shadowing
                                # the original exception.
                                connection.needs_rollback = True
                            raise
                else:
                    # Commit transaction
                    try:
>                       connection.commit()

.venv/lib/python3.13.../django/db/transaction.py:263: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

args = (<DatabaseWrapper vendor='postgresql' alias='default'>,), kwargs = {}

    @wraps(func)
    def inner(*args, **kwargs):
        # Detect a running event loop in this thread.
        try:
            get_running_loop()
        except RuntimeError:
            pass
        else:
            if not os.environ.get("DJANGO_ALLOW_ASYNC_UNSAFE"):
                raise SynchronousOnlyOperation(message)
        # Pass onward.
>       return func(*args, **kwargs)

.venv/lib/python3.13.../django/utils/asyncio.py:26: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DatabaseWrapper vendor='postgresql' alias='default'>

    @async_unsafe
    def commit(self):
        """Commit a transaction and reset the dirty flag."""
        self.validate_thread_sharing()
        self.validate_no_atomic_block()
>       self._commit()

.venv/lib/python3.13.../backends/base/base.py:327: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DatabaseWrapper vendor='postgresql' alias='default'>

    def _commit(self):
        if self.connection is not None:
>           with debug_transaction(self, "COMMIT"), self.wrap_database_errors:

.venv/lib/python3.13.../backends/base/base.py:302: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <django.db.utils.DatabaseErrorWrapper object at 0x7f47f519cec0>
exc_type = <class 'psycopg.errors.ForeignKeyViolation'>
exc_value = ForeignKeyViolation('insert or update on table "authentik_core_token" violates foreign key constraint "authentik_core_...ser_id_479d5b79_fk_authentik_core_user_id"\nDETAIL:  Key (user_id)=(2) is not present in table "authentik_core_user".')
traceback = <traceback object at 0x7f47e97c7540>

    def __exit__(self, exc_type, exc_value, traceback):
        if exc_type is None:
            return
        for dj_exc_type in (
            DataError,
            OperationalError,
            IntegrityError,
            InternalError,
            ProgrammingError,
            NotSupportedError,
            DatabaseError,
            InterfaceError,
            Error,
        ):
            db_exc_type = getattr(self.wrapper.Database, dj_exc_type.__name__)
            if issubclass(exc_type, db_exc_type):
                dj_exc_value = dj_exc_type(*exc_value.args)
                # Only set the 'errors_occurred' flag for errors that may make
                # the connection unusable.
                if dj_exc_type not in (DataError, IntegrityError):
                    self.wrapper.errors_occurred = True
>               raise dj_exc_value.with_traceback(traceback) from exc_value

.venv/lib/python3.13.../django/db/utils.py:91: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DatabaseWrapper vendor='postgresql' alias='default'>

    def _commit(self):
        if self.connection is not None:
            with debug_transaction(self, "COMMIT"), self.wrap_database_errors:
>               return self.connection.commit()

.venv/lib/python3.13.../backends/base/base.py:303: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <psycopg.Connection [BAD] at 0x7f47dc9da6c0>

    def commit(self) -> None:
        """Commit any pending transaction to the database."""
        with self.lock:
>           self.wait(self._commit_gen())

.venv/lib/python3.13............/site-packages/psycopg/connection.py:262: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <psycopg.Connection [BAD] at 0x7f47dc9da6c0>
gen = <generator object BaseConnection._commit_gen at 0x7f47dfe0de40>
interval = 0.1

    def wait(self, gen: PQGen[RV], interval: float | None = _WAIT_INTERVAL) -> RV:
        """
        Consume a generator operating on the connection.
    
        The function must be used on generators that don't change connection
        fd (i.e. not on connect and reset).
        """
        try:
>           return waiting.wait(gen, self.pgconn.socket, interval=interval)

.venv/lib/python3.13............/site-packages/psycopg/connection.py:414: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

>   ???

psycopg_c/_psycopg/waiting.pyx:213: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <psycopg.Connection [BAD] at 0x7f47dc9da6c0>

    def _commit_gen(self) -> PQGen[None]:
        """Generator implementing `Connection.commit()`."""
        if self._num_transactions:
            raise e.ProgrammingError(
                "Explicit commit() forbidden within a Transaction "
                "context. (Transaction will be automatically committed "
                "on successful exit from context.)"
            )
        if self._tpc:
            raise e.ProgrammingError(
                "commit() cannot be used during a two-phase transaction"
            )
        if self.pgconn.transaction_status == IDLE:
            return
    
>       yield from self._exec_command(b"COMMIT")

.venv/lib/python3.13............/site-packages/psycopg/_connection_base.py:580: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <psycopg.Connection [BAD] at 0x7f47dc9da6c0>, command = b'COMMIT'
result_format = <Format.TEXT: 0>

    def _exec_command(
        self, command: Query, result_format: pq.Format = TEXT
    ) -> PQGen[PGresult | None]:
        """
        Generator to send a command and receive the result to the backend.
    
        Only used to implement internal commands such as "commit", with eventual
        arguments bound client-side. The cursor can do more complex stuff.
        """
        self._check_connection_ok()
    
        if isinstance(command, str):
            command = command.encode(self.pgconn._encoding)
        elif isinstance(command, Composable):
            command = command.as_bytes(self)
    
        if self._pipeline:
            cmd = partial(
                self.pgconn.send_query_params,
                command,
                None,
                result_format=result_format,
            )
            self._pipeline.command_queue.append(cmd)
            self._pipeline.result_queue.append(None)
            return None
    
        # Unless needed, use the simple query protocol, e.g. to interact with
        # pgbouncer. In pipeline mode we always use the advanced query protocol
        # instead, see #350
        if result_format == TEXT:
            self.pgconn.send_query(command)
        else:
            self.pgconn.send_query_params(command, None, result_format=result_format)
    
        result: PGresult = (yield from generators.execute(self.pgconn))[-1]
        if result.status != COMMAND_OK and result.status != TUPLES_OK:
            if result.status == FATAL_ERROR:
>               raise e.error_from_result(result, encoding=self.pgconn._encoding)
E               django.db.utils.IntegrityError: insert or update on table "authentik_core_token" violates foreign key constraint "authentik_core_token_user_id_479d5b79_fk_authentik_core_user_id"
E               DETAIL:  Key (user_id)=(2) is not present in table "authentik_core_user".

.venv/lib/python3.13............/site-packages/psycopg/_connection_base.py:478: IntegrityError
authentik.tenants.tests.test_recovery.TestRecovery::test_recovery_admin_group
Stack Traces | 11.9s run time
self = <DatabaseWrapper vendor='postgresql' alias='default'>

    def _commit(self):
        if self.connection is not None:
            with debug_transaction(self, "COMMIT"), self.wrap_database_errors:
>               return self.connection.commit()

.venv/lib/python3.13.../backends/base/base.py:303: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <psycopg.Connection [BAD] at 0x7f47d4c5a300>

    def commit(self) -> None:
        """Commit any pending transaction to the database."""
        with self.lock:
>           self.wait(self._commit_gen())

.venv/lib/python3.13............/site-packages/psycopg/connection.py:262: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <psycopg.Connection [BAD] at 0x7f47d4c5a300>
gen = <generator object BaseConnection._commit_gen at 0x7f47d4ab4280>
interval = 0.1

    def wait(self, gen: PQGen[RV], interval: float | None = _WAIT_INTERVAL) -> RV:
        """
        Consume a generator operating on the connection.
    
        The function must be used on generators that don't change connection
        fd (i.e. not on connect and reset).
        """
        try:
>           return waiting.wait(gen, self.pgconn.socket, interval=interval)

.venv/lib/python3.13............/site-packages/psycopg/connection.py:414: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

>   ???

psycopg_c/_psycopg/waiting.pyx:213: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <psycopg.Connection [BAD] at 0x7f47d4c5a300>

    def _commit_gen(self) -> PQGen[None]:
        """Generator implementing `Connection.commit()`."""
        if self._num_transactions:
            raise e.ProgrammingError(
                "Explicit commit() forbidden within a Transaction "
                "context. (Transaction will be automatically committed "
                "on successful exit from context.)"
            )
        if self._tpc:
            raise e.ProgrammingError(
                "commit() cannot be used during a two-phase transaction"
            )
        if self.pgconn.transaction_status == IDLE:
            return
    
>       yield from self._exec_command(b"COMMIT")

.venv/lib/python3.13............/site-packages/psycopg/_connection_base.py:580: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <psycopg.Connection [BAD] at 0x7f47d4c5a300>, command = b'COMMIT'
result_format = <Format.TEXT: 0>

    def _exec_command(
        self, command: Query, result_format: pq.Format = TEXT
    ) -> PQGen[PGresult | None]:
        """
        Generator to send a command and receive the result to the backend.
    
        Only used to implement internal commands such as "commit", with eventual
        arguments bound client-side. The cursor can do more complex stuff.
        """
        self._check_connection_ok()
    
        if isinstance(command, str):
            command = command.encode(self.pgconn._encoding)
        elif isinstance(command, Composable):
            command = command.as_bytes(self)
    
        if self._pipeline:
            cmd = partial(
                self.pgconn.send_query_params,
                command,
                None,
                result_format=result_format,
            )
            self._pipeline.command_queue.append(cmd)
            self._pipeline.result_queue.append(None)
            return None
    
        # Unless needed, use the simple query protocol, e.g. to interact with
        # pgbouncer. In pipeline mode we always use the advanced query protocol
        # instead, see #350
        if result_format == TEXT:
            self.pgconn.send_query(command)
        else:
            self.pgconn.send_query_params(command, None, result_format=result_format)
    
        result: PGresult = (yield from generators.execute(self.pgconn))[-1]
        if result.status != COMMAND_OK and result.status != TUPLES_OK:
            if result.status == FATAL_ERROR:
>               raise e.error_from_result(result, encoding=self.pgconn._encoding)
E               psycopg.errors.ForeignKeyViolation: insert or update on table "authentik_core_token" violates foreign key constraint "authentik_core_token_user_id_479d5b79_fk_authentik_core_user_id"
E               DETAIL:  Key (user_id)=(2) is not present in table "authentik_core_user".

.venv/lib/python3.13............/site-packages/psycopg/_connection_base.py:478: ForeignKeyViolation

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

self = <unittest.case._Outcome object at 0x7f47df75fb60>
test_case = <authentik.tenants.tests.test_recovery.TestRecovery testMethod=test_recovery_admin_group>
subTest = False

    @contextlib.contextmanager
    def testPartExecutor(self, test_case, subTest=False):
        old_success = self.success
        self.success = True
        try:
>           yield

.../hostedtoolcache/Python/3.13.7........./x64/lib/python3.13/unittest/case.py:58: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <authentik.tenants.tests.test_recovery.TestRecovery testMethod=test_recovery_admin_group>
result = <TestCaseFunction test_recovery_admin_group>

    def run(self, result=None):
        if result is None:
            result = self.defaultTestResult()
            startTestRun = getattr(result, 'startTestRun', None)
            stopTestRun = getattr(result, 'stopTestRun', None)
            if startTestRun is not None:
                startTestRun()
        else:
            stopTestRun = None
    
        result.startTest(self)
        try:
            testMethod = getattr(self, self._testMethodName)
            if (getattr(self.__class__, "__unittest_skip__", False) or
                getattr(testMethod, "__unittest_skip__", False)):
                # If the class or method was skipped.
                skip_why = (getattr(self.__class__, '__unittest_skip_why__', '')
                            or getattr(testMethod, '__unittest_skip_why__', ''))
                _addSkip(result, self, skip_why)
                return result
    
            expecting_failure = (
                getattr(self, "__unittest_expecting_failure__", False) or
                getattr(testMethod, "__unittest_expecting_failure__", False)
            )
            outcome = _Outcome(result)
            start_time = time.perf_counter()
            try:
                self._outcome = outcome
    
                with outcome.testPartExecutor(self):
>                   self._callSetUp()

.../hostedtoolcache/Python/3.13.7........./x64/lib/python3.13/unittest/case.py:647: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <authentik.tenants.tests.test_recovery.TestRecovery testMethod=test_recovery_admin_group>

    def _callSetUp(self):
>       self.setUp()

.../hostedtoolcache/Python/3.13.7........./x64/lib/python3.13/unittest/case.py:603: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <authentik.tenants.tests.test_recovery.TestRecovery testMethod=test_recovery_admin_group>

    def setUp(self):
>       super().setUp()

.../tenants/tests/test_recovery.py:22: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <authentik.tenants.tests.test_recovery.TestRecovery testMethod=test_recovery_admin_group>

    def setUp(self):
        with schema_context(get_public_schema_name()):
>           Tenant.objects.update_or_create(
                defaults={"name": "Template", "ready": False},
                schema_name=get_tenant_base_schema(),
            )

.../tenants/tests/utils.py:24: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <django.db.models.manager.Manager object at 0x7f47e8ac5a50>, args = ()
kwargs = {'defaults': {'name': 'Template', 'ready': False}, 'schema_name': 'template'}

    @wraps(method)
    def manager_method(self, *args, **kwargs):
>       return getattr(self.get_queryset(), name)(*args, **kwargs)

.venv/lib/python3.13.../db/models/manager.py:87: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <QuerySet [<Tenant: Tenant Default>]>
defaults = {'name': 'Template', 'ready': False}
create_defaults = {'name': 'Template', 'ready': False}
kwargs = {'schema_name': 'template'}
update_defaults = {'name': 'Template', 'ready': False}
obj = <Tenant: Tenant Template>, created = True

    def update_or_create(self, defaults=None, create_defaults=None, **kwargs):
        """
        Look up an object with the given kwargs, updating one with defaults
        if it exists, otherwise create a new one. Optionally, an object can
        be created with different values than defaults by using
        create_defaults.
        Return a tuple (object, created), where created is a boolean
        specifying whether an object was created.
        """
        update_defaults = defaults or {}
        if create_defaults is None:
            create_defaults = update_defaults
    
        self._for_write = True
>       with transaction.atomic(using=self.db):

.venv/lib/python3.13.../db/models/query.py:985: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <django.db.transaction.Atomic object at 0x7f47eaa53150>, exc_type = None
exc_value = None, traceback = None

    def __exit__(self, exc_type, exc_value, traceback):
        connection = get_connection(self.using)
    
        if connection.in_atomic_block:
            connection.atomic_blocks.pop()
    
        if connection.savepoint_ids:
            sid = connection.savepoint_ids.pop()
        else:
            # Prematurely unset this flag to allow using commit or rollback.
            connection.in_atomic_block = False
    
        try:
            if connection.closed_in_transaction:
                # The database will perform a rollback by itself.
                # Wait until we exit the outermost block.
                pass
    
            elif exc_type is None and not connection.needs_rollback:
                if connection.in_atomic_block:
                    # Release savepoint if there is one
                    if sid is not None:
                        try:
                            connection.savepoint_commit(sid)
                        except DatabaseError:
                            try:
                                connection.savepoint_rollback(sid)
                                # The savepoint won't be reused. Release it to
                                # minimize overhead for the database server.
                                connection.savepoint_commit(sid)
                            except Error:
                                # If rolling back to a savepoint fails, mark for
                                # rollback at a higher level and avoid shadowing
                                # the original exception.
                                connection.needs_rollback = True
                            raise
                else:
                    # Commit transaction
                    try:
>                       connection.commit()

.venv/lib/python3.13.../django/db/transaction.py:263: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

args = (<DatabaseWrapper vendor='postgresql' alias='default'>,), kwargs = {}

    @wraps(func)
    def inner(*args, **kwargs):
        # Detect a running event loop in this thread.
        try:
            get_running_loop()
        except RuntimeError:
            pass
        else:
            if not os.environ.get("DJANGO_ALLOW_ASYNC_UNSAFE"):
                raise SynchronousOnlyOperation(message)
        # Pass onward.
>       return func(*args, **kwargs)

.venv/lib/python3.13.../django/utils/asyncio.py:26: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DatabaseWrapper vendor='postgresql' alias='default'>

    @async_unsafe
    def commit(self):
        """Commit a transaction and reset the dirty flag."""
        self.validate_thread_sharing()
        self.validate_no_atomic_block()
>       self._commit()

.venv/lib/python3.13.../backends/base/base.py:327: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DatabaseWrapper vendor='postgresql' alias='default'>

    def _commit(self):
        if self.connection is not None:
>           with debug_transaction(self, "COMMIT"), self.wrap_database_errors:

.venv/lib/python3.13.../backends/base/base.py:302: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <django.db.utils.DatabaseErrorWrapper object at 0x7f47f519cec0>
exc_type = <class 'psycopg.errors.ForeignKeyViolation'>
exc_value = ForeignKeyViolation('insert or update on table "authentik_core_token" violates foreign key constraint "authentik_core_...ser_id_479d5b79_fk_authentik_core_user_id"\nDETAIL:  Key (user_id)=(2) is not present in table "authentik_core_user".')
traceback = <traceback object at 0x7f47e9211140>

    def __exit__(self, exc_type, exc_value, traceback):
        if exc_type is None:
            return
        for dj_exc_type in (
            DataError,
            OperationalError,
            IntegrityError,
            InternalError,
            ProgrammingError,
            NotSupportedError,
            DatabaseError,
            InterfaceError,
            Error,
        ):
            db_exc_type = getattr(self.wrapper.Database, dj_exc_type.__name__)
            if issubclass(exc_type, db_exc_type):
                dj_exc_value = dj_exc_type(*exc_value.args)
                # Only set the 'errors_occurred' flag for errors that may make
                # the connection unusable.
                if dj_exc_type not in (DataError, IntegrityError):
                    self.wrapper.errors_occurred = True
>               raise dj_exc_value.with_traceback(traceback) from exc_value

.venv/lib/python3.13.../django/db/utils.py:91: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DatabaseWrapper vendor='postgresql' alias='default'>

    def _commit(self):
        if self.connection is not None:
            with debug_transaction(self, "COMMIT"), self.wrap_database_errors:
>               return self.connection.commit()

.venv/lib/python3.13.../backends/base/base.py:303: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <psycopg.Connection [BAD] at 0x7f47d4c5a300>

    def commit(self) -> None:
        """Commit any pending transaction to the database."""
        with self.lock:
>           self.wait(self._commit_gen())

.venv/lib/python3.13............/site-packages/psycopg/connection.py:262: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <psycopg.Connection [BAD] at 0x7f47d4c5a300>
gen = <generator object BaseConnection._commit_gen at 0x7f47d4ab4280>
interval = 0.1

    def wait(self, gen: PQGen[RV], interval: float | None = _WAIT_INTERVAL) -> RV:
        """
        Consume a generator operating on the connection.
    
        The function must be used on generators that don't change connection
        fd (i.e. not on connect and reset).
        """
        try:
>           return waiting.wait(gen, self.pgconn.socket, interval=interval)

.venv/lib/python3.13............/site-packages/psycopg/connection.py:414: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

>   ???

psycopg_c/_psycopg/waiting.pyx:213: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <psycopg.Connection [BAD] at 0x7f47d4c5a300>

    def _commit_gen(self) -> PQGen[None]:
        """Generator implementing `Connection.commit()`."""
        if self._num_transactions:
            raise e.ProgrammingError(
                "Explicit commit() forbidden within a Transaction "
                "context. (Transaction will be automatically committed "
                "on successful exit from context.)"
            )
        if self._tpc:
            raise e.ProgrammingError(
                "commit() cannot be used during a two-phase transaction"
            )
        if self.pgconn.transaction_status == IDLE:
            return
    
>       yield from self._exec_command(b"COMMIT")

.venv/lib/python3.13............/site-packages/psycopg/_connection_base.py:580: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <psycopg.Connection [BAD] at 0x7f47d4c5a300>, command = b'COMMIT'
result_format = <Format.TEXT: 0>

    def _exec_command(
        self, command: Query, result_format: pq.Format = TEXT
    ) -> PQGen[PGresult | None]:
        """
        Generator to send a command and receive the result to the backend.
    
        Only used to implement internal commands such as "commit", with eventual
        arguments bound client-side. The cursor can do more complex stuff.
        """
        self._check_connection_ok()
    
        if isinstance(command, str):
            command = command.encode(self.pgconn._encoding)
        elif isinstance(command, Composable):
            command = command.as_bytes(self)
    
        if self._pipeline:
            cmd = partial(
                self.pgconn.send_query_params,
                command,
                None,
                result_format=result_format,
            )
            self._pipeline.command_queue.append(cmd)
            self._pipeline.result_queue.append(None)
            return None
    
        # Unless needed, use the simple query protocol, e.g. to interact with
        # pgbouncer. In pipeline mode we always use the advanced query protocol
        # instead, see #350
        if result_format == TEXT:
            self.pgconn.send_query(command)
        else:
            self.pgconn.send_query_params(command, None, result_format=result_format)
    
        result: PGresult = (yield from generators.execute(self.pgconn))[-1]
        if result.status != COMMAND_OK and result.status != TUPLES_OK:
            if result.status == FATAL_ERROR:
>               raise e.error_from_result(result, encoding=self.pgconn._encoding)
E               django.db.utils.IntegrityError: insert or update on table "authentik_core_token" violates foreign key constraint "authentik_core_token_user_id_479d5b79_fk_authentik_core_user_id"
E               DETAIL:  Key (user_id)=(2) is not present in table "authentik_core_user".

.venv/lib/python3.13............/site-packages/psycopg/_connection_base.py:478: IntegrityError
authentik.tenants.tests.test_domain.TestDomainAPI::test_domain
Stack Traces | 12.1s run time
self = <DatabaseWrapper vendor='postgresql' alias='default'>

    def _commit(self):
        if self.connection is not None:
            with debug_transaction(self, "COMMIT"), self.wrap_database_errors:
>               return self.connection.commit()

.venv/lib/python3.13.../backends/base/base.py:303: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <psycopg.Connection [BAD] at 0x7f47d4912e40>

    def commit(self) -> None:
        """Commit any pending transaction to the database."""
        with self.lock:
>           self.wait(self._commit_gen())

.venv/lib/python3.13............/site-packages/psycopg/connection.py:262: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <psycopg.Connection [BAD] at 0x7f47d4912e40>
gen = <generator object BaseConnection._commit_gen at 0x7f47d452c640>
interval = 0.1

    def wait(self, gen: PQGen[RV], interval: float | None = _WAIT_INTERVAL) -> RV:
        """
        Consume a generator operating on the connection.
    
        The function must be used on generators that don't change connection
        fd (i.e. not on connect and reset).
        """
        try:
>           return waiting.wait(gen, self.pgconn.socket, interval=interval)

.venv/lib/python3.13............/site-packages/psycopg/connection.py:414: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

>   ???

psycopg_c/_psycopg/waiting.pyx:213: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <psycopg.Connection [BAD] at 0x7f47d4912e40>

    def _commit_gen(self) -> PQGen[None]:
        """Generator implementing `Connection.commit()`."""
        if self._num_transactions:
            raise e.ProgrammingError(
                "Explicit commit() forbidden within a Transaction "
                "context. (Transaction will be automatically committed "
                "on successful exit from context.)"
            )
        if self._tpc:
            raise e.ProgrammingError(
                "commit() cannot be used during a two-phase transaction"
            )
        if self.pgconn.transaction_status == IDLE:
            return
    
>       yield from self._exec_command(b"COMMIT")

.venv/lib/python3.13............/site-packages/psycopg/_connection_base.py:580: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <psycopg.Connection [BAD] at 0x7f47d4912e40>, command = b'COMMIT'
result_format = <Format.TEXT: 0>

    def _exec_command(
        self, command: Query, result_format: pq.Format = TEXT
    ) -> PQGen[PGresult | None]:
        """
        Generator to send a command and receive the result to the backend.
    
        Only used to implement internal commands such as "commit", with eventual
        arguments bound client-side. The cursor can do more complex stuff.
        """
        self._check_connection_ok()
    
        if isinstance(command, str):
            command = command.encode(self.pgconn._encoding)
        elif isinstance(command, Composable):
            command = command.as_bytes(self)
    
        if self._pipeline:
            cmd = partial(
                self.pgconn.send_query_params,
                command,
                None,
                result_format=result_format,
            )
            self._pipeline.command_queue.append(cmd)
            self._pipeline.result_queue.append(None)
            return None
    
        # Unless needed, use the simple query protocol, e.g. to interact with
        # pgbouncer. In pipeline mode we always use the advanced query protocol
        # instead, see #350
        if result_format == TEXT:
            self.pgconn.send_query(command)
        else:
            self.pgconn.send_query_params(command, None, result_format=result_format)
    
        result: PGresult = (yield from generators.execute(self.pgconn))[-1]
        if result.status != COMMAND_OK and result.status != TUPLES_OK:
            if result.status == FATAL_ERROR:
>               raise e.error_from_result(result, encoding=self.pgconn._encoding)
E               psycopg.errors.ForeignKeyViolation: insert or update on table "authentik_core_token" violates foreign key constraint "authentik_core_token_user_id_479d5b79_fk_authentik_core_user_id"
E               DETAIL:  Key (user_id)=(2) is not present in table "authentik_core_user".

.venv/lib/python3.13............/site-packages/psycopg/_connection_base.py:478: ForeignKeyViolation

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

self = <unittest.case._Outcome object at 0x7f47eaa8e350>
test_case = <authentik.tenants.tests.test_domain.TestDomainAPI testMethod=test_domain>
subTest = False

    @contextlib.contextmanager
    def testPartExecutor(self, test_case, subTest=False):
        old_success = self.success
        self.success = True
        try:
>           yield

.../hostedtoolcache/Python/3.13.7........./x64/lib/python3.13/unittest/case.py:58: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <authentik.tenants.tests.test_domain.TestDomainAPI testMethod=test_domain>
result = <TestCaseFunction test_domain>

    def run(self, result=None):
        if result is None:
            result = self.defaultTestResult()
            startTestRun = getattr(result, 'startTestRun', None)
            stopTestRun = getattr(result, 'stopTestRun', None)
            if startTestRun is not None:
                startTestRun()
        else:
            stopTestRun = None
    
        result.startTest(self)
        try:
            testMethod = getattr(self, self._testMethodName)
            if (getattr(self.__class__, "__unittest_skip__", False) or
                getattr(testMethod, "__unittest_skip__", False)):
                # If the class or method was skipped.
                skip_why = (getattr(self.__class__, '__unittest_skip_why__', '')
                            or getattr(testMethod, '__unittest_skip_why__', ''))
                _addSkip(result, self, skip_why)
                return result
    
            expecting_failure = (
                getattr(self, "__unittest_expecting_failure__", False) or
                getattr(testMethod, "__unittest_expecting_failure__", False)
            )
            outcome = _Outcome(result)
            start_time = time.perf_counter()
            try:
                self._outcome = outcome
    
                with outcome.testPartExecutor(self):
>                   self._callSetUp()

.../hostedtoolcache/Python/3.13.7........./x64/lib/python3.13/unittest/case.py:647: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <authentik.tenants.tests.test_domain.TestDomainAPI testMethod=test_domain>

    def _callSetUp(self):
>       self.setUp()

.../hostedtoolcache/Python/3.13.7........./x64/lib/python3.13/unittest/case.py:603: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <authentik.tenants.tests.test_domain.TestDomainAPI testMethod=test_domain>

    def setUp(self):
>       super().setUp()

.../tenants/tests/test_domain.py:18: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <authentik.tenants.tests.test_domain.TestDomainAPI testMethod=test_domain>

    def setUp(self):
        with schema_context(get_public_schema_name()):
>           Tenant.objects.update_or_create(
                defaults={"name": "Template", "ready": False},
                schema_name=get_tenant_base_schema(),
            )

.../tenants/tests/utils.py:24: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <django.db.models.manager.Manager object at 0x7f47e8ac5a50>, args = ()
kwargs = {'defaults': {'name': 'Template', 'ready': False}, 'schema_name': 'template'}

    @wraps(method)
    def manager_method(self, *args, **kwargs):
>       return getattr(self.get_queryset(), name)(*args, **kwargs)

.venv/lib/python3.13.../db/models/manager.py:87: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <QuerySet [<Tenant: Tenant Default>]>
defaults = {'name': 'Template', 'ready': False}
create_defaults = {'name': 'Template', 'ready': False}
kwargs = {'schema_name': 'template'}
update_defaults = {'name': 'Template', 'ready': False}
obj = <Tenant: Tenant Template>, created = True

    def update_or_create(self, defaults=None, create_defaults=None, **kwargs):
        """
        Look up an object with the given kwargs, updating one with defaults
        if it exists, otherwise create a new one. Optionally, an object can
        be created with different values than defaults by using
        create_defaults.
        Return a tuple (object, created), where created is a boolean
        specifying whether an object was created.
        """
        update_defaults = defaults or {}
        if create_defaults is None:
            create_defaults = update_defaults
    
        self._for_write = True
>       with transaction.atomic(using=self.db):

.venv/lib/python3.13.../db/models/query.py:985: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <django.db.transaction.Atomic object at 0x7f47e8e4e5f0>, exc_type = None
exc_value = None, traceback = None

    def __exit__(self, exc_type, exc_value, traceback):
        connection = get_connection(self.using)
    
        if connection.in_atomic_block:
            connection.atomic_blocks.pop()
    
        if connection.savepoint_ids:
            sid = connection.savepoint_ids.pop()
        else:
            # Prematurely unset this flag to allow using commit or rollback.
            connection.in_atomic_block = False
    
        try:
            if connection.closed_in_transaction:
                # The database will perform a rollback by itself.
                # Wait until we exit the outermost block.
                pass
    
            elif exc_type is None and not connection.needs_rollback:
                if connection.in_atomic_block:
                    # Release savepoint if there is one
                    if sid is not None:
                        try:
                            connection.savepoint_commit(sid)
                        except DatabaseError:
                            try:
                                connection.savepoint_rollback(sid)
                                # The savepoint won't be reused. Release it to
                                # minimize overhead for the database server.
                                connection.savepoint_commit(sid)
                            except Error:
                                # If rolling back to a savepoint fails, mark for
                                # rollback at a higher level and avoid shadowing
                                # the original exception.
                                connection.needs_rollback = True
                            raise
                else:
                    # Commit transaction
                    try:
>                       connection.commit()

.venv/lib/python3.13.../django/db/transaction.py:263: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

args = (<DatabaseWrapper vendor='postgresql' alias='default'>,), kwargs = {}

    @wraps(func)
    def inner(*args, **kwargs):
        # Detect a running event loop in this thread.
        try:
            get_running_loop()
        except RuntimeError:
            pass
        else:
            if not os.environ.get("DJANGO_ALLOW_ASYNC_UNSAFE"):
                raise SynchronousOnlyOperation(message)
        # Pass onward.
>       return func(*args, **kwargs)

.venv/lib/python3.13.../django/utils/asyncio.py:26: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DatabaseWrapper vendor='postgresql' alias='default'>

    @async_unsafe
    def commit(self):
        """Commit a transaction and reset the dirty flag."""
        self.validate_thread_sharing()
        self.validate_no_atomic_block()
>       self._commit()

.venv/lib/python3.13.../backends/base/base.py:327: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DatabaseWrapper vendor='postgresql' alias='default'>

    def _commit(self):
        if self.connection is not None:
>           with debug_transaction(self, "COMMIT"), self.wrap_database_errors:

.venv/lib/python3.13.../backends/base/base.py:302: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <django.db.utils.DatabaseErrorWrapper object at 0x7f47f519cec0>
exc_type = <class 'psycopg.errors.ForeignKeyViolation'>
exc_value = ForeignKeyViolation('insert or update on table "authentik_core_token" violates foreign key constraint "authentik_core_...ser_id_479d5b79_fk_authentik_core_user_id"\nDETAIL:  Key (user_id)=(2) is not present in table "authentik_core_user".')
traceback = <traceback object at 0x7f47d4c9bbc0>

    def __exit__(self, exc_type, exc_value, traceback):
        if exc_type is None:
            return
        for dj_exc_type in (
            DataError,
            OperationalError,
            IntegrityError,
            InternalError,
            ProgrammingError,
            NotSupportedError,
            DatabaseError,
            InterfaceError,
            Error,
        ):
            db_exc_type = getattr(self.wrapper.Database, dj_exc_type.__name__)
            if issubclass(exc_type, db_exc_type):
                dj_exc_value = dj_exc_type(*exc_value.args)
                # Only set the 'errors_occurred' flag for errors that may make
                # the connection unusable.
                if dj_exc_type not in (DataError, IntegrityError):
                    self.wrapper.errors_occurred = True
>               raise dj_exc_value.with_traceback(traceback) from exc_value

.venv/lib/python3.13.../django/db/utils.py:91: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DatabaseWrapper vendor='postgresql' alias='default'>

    def _commit(self):
        if self.connection is not None:
            with debug_transaction(self, "COMMIT"), self.wrap_database_errors:
>               return self.connection.commit()

.venv/lib/python3.13.../backends/base/base.py:303: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <psycopg.Connection [BAD] at 0x7f47d4912e40>

    def commit(self) -> None:
        """Commit any pending transaction to the database."""
        with self.lock:
>           self.wait(self._commit_gen())

.venv/lib/python3.13............/site-packages/psycopg/connection.py:262: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <psycopg.Connection [BAD] at 0x7f47d4912e40>
gen = <generator object BaseConnection._commit_gen at 0x7f47d452c640>
interval = 0.1

    def wait(self, gen: PQGen[RV], interval: float | None = _WAIT_INTERVAL) -> RV:
        """
        Consume a generator operating on the connection.
    
        The function must be used on generators that don't change connection
        fd (i.e. not on connect and reset).
        """
        try:
>           return waiting.wait(gen, self.pgconn.socket, interval=interval)

.venv/lib/python3.13............/site-packages/psycopg/connection.py:414: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

>   ???

psycopg_c/_psycopg/waiting.pyx:213: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <psycopg.Connection [BAD] at 0x7f47d4912e40>

    def _commit_gen(self) -> PQGen[None]:
        """Generator implementing `Connection.commit()`."""
        if self._num_transactions:
            raise e.ProgrammingError(
                "Explicit commit() forbidden within a Transaction "
                "context. (Transaction will be automatically committed "
                "on successful exit from context.)"
            )
        if self._tpc:
            raise e.ProgrammingError(
                "commit() cannot be used during a two-phase transaction"
            )
        if self.pgconn.transaction_status == IDLE:
            return
    
>       yield from self._exec_command(b"COMMIT")

.venv/lib/python3.13............/site-packages/psycopg/_connection_base.py:580: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <psycopg.Connection [BAD] at 0x7f47d4912e40>, command = b'COMMIT'
result_format = <Format.TEXT: 0>

    def _exec_command(
        self, command: Query, result_format: pq.Format = TEXT
    ) -> PQGen[PGresult | None]:
        """
        Generator to send a command and receive the result to the backend.
    
        Only used to implement internal commands such as "commit", with eventual
        arguments bound client-side. The cursor can do more complex stuff.
        """
        self._check_connection_ok()
    
        if isinstance(command, str):
            command = command.encode(self.pgconn._encoding)
        elif isinstance(command, Composable):
            command = command.as_bytes(self)
    
        if self._pipeline:
            cmd = partial(
                self.pgconn.send_query_params,
                command,
                None,
                result_format=result_format,
            )
            self._pipeline.command_queue.append(cmd)
            self._pipeline.result_queue.append(None)
            return None
    
        # Unless needed, use the simple query protocol, e.g. to interact with
        # pgbouncer. In pipeline mode we always use the advanced query protocol
        # instead, see #350
        if result_format == TEXT:
            self.pgconn.send_query(command)
        else:
            self.pgconn.send_query_params(command, None, result_format=result_format)
    
        result: PGresult = (yield from generators.execute(self.pgconn))[-1]
        if result.status != COMMAND_OK and result.status != TUPLES_OK:
            if result.status == FATAL_ERROR:
>               raise e.error_from_result(result, encoding=self.pgconn._encoding)
E               django.db.utils.IntegrityError: insert or update on table "authentik_core_token" violates foreign key constraint "authentik_core_token_user_id_479d5b79_fk_authentik_core_user_id"
E               DETAIL:  Key (user_id)=(2) is not present in table "authentik_core_user".

.venv/lib/python3.13............/site-packages/psycopg/_connection_base.py:478: IntegrityError
tests.e2e.test_provider_saml.TestProviderSAML::test_sp_initiated_implicit_post_buffer
Stack Traces | 239s run time
self = <tests.e2e.test_provider_saml.TestProviderSAML testMethod=test_sp_initiated_implicit_post_buffer>
args = (), kwargs = {}

    @wraps(func)
    def wrapper(self: TransactionTestCase, *args, **kwargs):
        """Run test again if we're below max_retries, including tearDown and
        setUp. Otherwise raise the error"""
        nonlocal count
        try:
>           return func(self, *args, **kwargs)

tests/e2e/utils.py:324: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

args = (<tests.e2e.test_provider_saml.TestProviderSAML testMethod=test_sp_initiated_implicit_post_buffer>,)
kwargs = {}, file = 'default/flow-default-invalidation-flow.yaml'
content = 'version: 1\nmetadata:\n  name: Default - Invalidation flow\nentries:\n- attrs:\n    designation: invalidation\n    na...0\n    stage: !KeyOf default-invalidation-logout\n    target: !KeyOf flow\n  model: authentik_flows.flowstagebinding\n'

    @wraps(func)
    def wrapper(*args, **kwargs):
        for file in files:
            content = BlueprintInstance(path=file).retrieve()
            Importer.from_string(content).apply()
>       return func(*args, **kwargs)

.../blueprints/tests/__init__.py:25: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

args = (<tests.e2e.test_provider_saml.TestProviderSAML testMethod=test_sp_initiated_implicit_post_buffer>,)
kwargs = {}
file = 'default/flow-default-provider-authorization-implicit-consent.yaml'
content = 'version: 1\nmetadata:\n  name: Default - Provider authorization flow (implicit consent)\nentries:\n- attrs:\n    desi...henticated\n  identifiers:\n    slug: default-provider-authorization-implicit-consent\n  model: authentik_flows.flow\n'

    @wraps(func)
    def wrapper(*args, **kwargs):
        for file in files:
            content = BlueprintInstance(path=file).retrieve()
            Importer.from_string(content).apply()
>       return func(*args, **kwargs)

.../blueprints/tests/__init__.py:25: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

args = (<tests.e2e.test_provider_saml.TestProviderSAML testMethod=test_sp_initiated_implicit_post_buffer>,)
kwargs = {}, file = 'system/providers-saml.yaml'
content = 'version: 1\nmetadata:\n  labels:\n    blueprints.goauthentik.io/system: "true"\n  name: System - SAML Provider - Mapp...rosoft..../identity/claims/windowsaccountname"\n      expression: |\n        return request.user.username\n'

    @wraps(func)
    def wrapper(*args, **kwargs):
        for file in files:
            content = BlueprintInstance(path=file).retrieve()
            Importer.from_string(content).apply()
>       return func(*args, **kwargs)

.../blueprints/tests/__init__.py:25: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

args = (<tests.e2e.test_provider_saml.TestProviderSAML testMethod=test_sp_initiated_implicit_post_buffer>,)
kwargs = {}, config = <AuthentikCryptoConfig: authentik_crypto>

    @wraps(func)
    def wrapper(*args, **kwargs):
        config = apps.get_app_config(app_name)
        if isinstance(config, ManagedAppConfig):
            config._on_startup_callback(None)
>       return func(*args, **kwargs)

.../blueprints/tests/__init__.py:43: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

args = (<tests.e2e.test_provider_saml.TestProviderSAML testMethod=test_sp_initiated_implicit_post_buffer>,)
kwargs = {}, tenant = <Tenant: Tenant Default>

    @wraps(func)
    def wrapper(*args, **kwargs):
        tenant = get_current_tenant()
        tenant.flags[flag().key] = value
        tenant.save()
>       return func(*args, **kwargs)

authentik/tenants/flags.py:54: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <tests.e2e.test_provider_saml.TestProviderSAML testMethod=test_sp_initiated_implicit_post_buffer>

    @retry()
    @apply_blueprint(
        "default/flow-default-authentication-flow.yaml",
        "default/flow-default-invalidation-flow.yaml",
    )
    @apply_blueprint(
        "default/flow-default-provider-authorization-implicit-consent.yaml",
    )
    @apply_blueprint(
        "system/providers-saml.yaml",
    )
    @reconcile_app("authentik_crypto")
    @patch_flag(BufferedPolicyAccessViewFlag, True)
    def test_sp_initiated_implicit_post_buffer(self):
        """test SAML Provider flow SP-initiated flow (implicit consent)"""
        # Bootstrap all needed objects
        authorization_flow = Flow.objects.get(
            slug="default-provider-authorization-implicit-consent"
        )
        provider: SAMLProvider = SAMLProvider.objects.create(
            name=generate_id(),
            acs_url=f"http://{self.host}:9009/saml/acs",
            audience="authentik-e2e",
            issuer="authentik-e2e",
            sp_binding=SAMLBindings.POST,
            authorization_flow=authorization_flow,
            signing_kp=create_test_cert(),
        )
        provider.property_mappings.set(SAMLPropertyMapping.objects.all())
        provider.save()
        Application.objects.create(
            name="SAML",
            slug=generate_id(),
            provider=provider,
        )
        self.setup_client(provider, True, SP_ROOT_URL=f"http://{self.host}:9009")
    
        self.driver.get(self.live_server_url)
        login_window = self.driver.current_window_handle
        self.driver.switch_to.new_window("tab")
        client_window = self.driver.current_window_handle
        # We need to access the SP on the same host as the IdP for SameSite cookies
        self.driver.get(f"http://{self.host}:9009")
        self.driver.switch_to.new_window("tab")
        client_window = self.driver.current_window_handle
        # We need to access the SP on the same host as the IdP for SameSite cookies
        self.driver.get(f"http://{self.host}:9009")
        self.driver.switch_to.new_window("tab")
        client_window = self.driver.current_window_handle
        # We need to access the SP on the same host as the IdP for SameSite cookies
        self.driver.get(f"http://{self.host}:9009")
        self.driver.switch_to.new_window("tab")
        client_window = self.driver.current_window_handle
        # We need to access the SP on the same host as the IdP for SameSite cookies
        self.driver.get(f"http://{self.host}:9009")
        self.driver.switch_to.new_window("tab")
        client_window = self.driver.current_window_handle
        # We need to access the SP on the same host as the IdP for SameSite cookies
        self.driver.get(f"http://{self.host}:9009")
    
        self.driver.switch_to.window(login_window)
        self.login()
        self.driver.switch_to.window(client_window)
    
>       self.wait_for_url(f"http://{self.host}:9009/")

tests/e2e/test_provider_saml.py:590: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <tests.e2e.test_provider_saml.TestProviderSAML testMethod=test_sp_initiated_implicit_post_buffer>
desired_url = 'http://10.1.0.138:9009/'

    def wait_for_url(self, desired_url):
        """Wait until URL is `desired_url`."""
>       self.wait.until(
            lambda driver: driver.current_url == desired_url,
            f"URL {self.driver.current_url} doesn't match expected URL {desired_url}",
        )

tests/e2e/utils.py:211: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <selenium.webdriver.support.wait.WebDriverWait (session="53672d42145ad1a79307f71612b19110")>
method = <function SeleniumTestCase.wait_for_url.<locals>.<lambda> at 0x7fa440925d00>
message = "URL http://10.1.0.138:32821/policy/buffer?af_bf_id=ed987967-5647-4058-a9c7-16c2f4e61408 doesn't match expected URL http://10.1.0.138:9009/"

    def until(self, method: Callable[[D], Union[Literal[False], T]], message: str = "") -> T:
        """Wait until the method returns a value that is not False.
    
        Calls the method provided with the driver as an argument until the
        return value does not evaluate to ``False``.
    
        Parameters:
        -----------
        method: callable(WebDriver)
            - A callable object that takes a WebDriver instance as an argument.
    
        message: str
            - Optional message for :exc:`TimeoutException`
    
        Return:
        -------
        object: T
            - The result of the last call to `method`
    
        Raises:
        -------
        TimeoutException
            - If 'method' does not return a truthy value within the WebDriverWait
            object's timeout
    
        Example:
        --------
        >>> from selenium.webdriver.common.by import By
        >>> from selenium.webdriver.support.ui import WebDriverWait
        >>> from selenium.webdriver.support import expected_conditions as EC
    
        # Wait until an element is visible on the page
        >>> wait = WebDriverWait(driver, 10)
        >>> element = wait.until(EC.visibility_of_element_located((By.ID, "exampleId")))
        >>> print(element.text)
        """
        screen = None
        stacktrace = None
    
        end_time = time.monotonic() + self._timeout
        while True:
            try:
                value = method(self._driver)
                if value:
                    return value
            except self._ignored_exceptions as exc:
                screen = getattr(exc, "screen", None)
                stacktrace = getattr(exc, "stacktrace", None)
            if time.monotonic() > end_time:
                break
            time.sleep(self._poll)
>       raise TimeoutException(message, screen, stacktrace)
E       selenium.common.exceptions.TimeoutException: Message: URL http://10.1.0.138:32821/policy/buffer?af_bf_id=ed987967-5647-4058-a9c7-16c2f4e61408 doesn't match expected URL http://10.1.0.138:9009/

.venv/lib/python3.13.../webdriver/support/wait.py:146: TimeoutException

During handling of the above exception, another exception occurred:

self = <tests.e2e.test_provider_saml.TestProviderSAML testMethod=test_sp_initiated_implicit_post_buffer>
args = (), kwargs = {}

    @wraps(func)
    def wrapper(self: TransactionTestCase, *args, **kwargs):
        """Run test again if we're below max_retries, including tearDown and
        setUp. Otherwise raise the error"""
        nonlocal count
        try:
>           return func(self, *args, **kwargs)

tests/e2e/utils.py:324: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

args = (<tests.e2e.test_provider_saml.TestProviderSAML testMethod=test_sp_initiated_implicit_post_buffer>,)
kwargs = {}, file = 'default/flow-default-invalidation-flow.yaml'
content = 'version: 1\nmetadata:\n  name: Default - Invalidation flow\nentries:\n- attrs:\n    designation: invalidation\n    na...0\n    stage: !KeyOf default-invalidation-logout\n    target: !KeyOf flow\n  model: authentik_flows.flowstagebinding\n'

    @wraps(func)
    def wrapper(*args, **kwargs):
        for file in files:
            content = BlueprintInstance(path=file).retrieve()
            Importer.from_string(content).apply()
>       return func(*args, **kwargs)

.../blueprints/tests/__init__.py:25: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

args = (<tests.e2e.test_provider_saml.TestProviderSAML testMethod=test_sp_initiated_implicit_post_buffer>,)
kwargs = {}
file = 'default/flow-default-provider-authorization-implicit-consent.yaml'
content = 'version: 1\nmetadata:\n  name: Default - Provider authorization flow (implicit consent)\nentries:\n- attrs:\n    desi...henticated\n  identifiers:\n    slug: default-provider-authorization-implicit-consent\n  model: authentik_flows.flow\n'

    @wraps(func)
    def wrapper(*args, **kwargs):
        for file in files:
            content = BlueprintInstance(path=file).retrieve()
            Importer.from_string(content).apply()
>       return func(*args, **kwargs)

.../blueprints/tests/__init__.py:25: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

args = (<tests.e2e.test_provider_saml.TestProviderSAML testMethod=test_sp_initiated_implicit_post_buffer>,)
kwargs = {}, file = 'system/providers-saml.yaml'
content = 'version: 1\nmetadata:\n  labels:\n    blueprints.goauthentik.io/system: "true"\n  name: System - SAML Provider - Mapp...rosoft..../identity/claims/windowsaccountname"\n      expression: |\n        return request.user.username\n'

    @wraps(func)
    def wrapper(*args, **kwargs):
        for file in files:
            content = BlueprintInstance(path=file).retrieve()
            Importer.from_string(content).apply()
>       return func(*args, **kwargs)

.../blueprints/tests/__init__.py:25: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

args = (<tests.e2e.test_provider_saml.TestProviderSAML testMethod=test_sp_initiated_implicit_post_buffer>,)
kwargs = {}, config = <AuthentikCryptoConfig: authentik_crypto>

    @wraps(func)
    def wrapper(*args, **kwargs):
        config = apps.get_app_config(app_name)
        if isinstance(config, ManagedAppConfig):
            config._on_startup_callback(None)
>       return func(*args, **kwargs)

.../blueprints/tests/__init__.py:43: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

args = (<tests.e2e.test_provider_saml.TestProviderSAML testMethod=test_sp_initiated_implicit_post_buffer>,)
kwargs = {}, tenant = <Tenant: Tenant Default>

    @wraps(func)
    def wrapper(*args, **kwargs):
        tenant = get_current_tenant()
        tenant.flags[flag().key] = value
        tenant.save()
>       return func(*args, **kwargs)

authentik/tenants/flags.py:54: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <tests.e2e.test_provider_saml.TestProviderSAML testMethod=test_sp_initiated_implicit_post_buffer>

    @retry()
    @apply_blueprint(
        "default/flow-default-authentication-flow.yaml",
        "default/flow-default-invalidation-flow.yaml",
    )
    @apply_blueprint(
        "default/flow-default-provider-authorization-implicit-consent.yaml",
    )
    @apply_blueprint(
        "system/providers-saml.yaml",
    )
    @reconcile_app("authentik_crypto")
    @patch_flag(BufferedPolicyAccessViewFlag, True)
    def test_sp_initiated_implicit_post_buffer(self):
        """test SAML Provider flow SP-initiated flow (implicit consent)"""
        # Bootstrap all needed objects
        authorization_flow = Flow.objects.get(
            slug="default-provider-authorization-implicit-consent"
        )
        provider: SAMLProvider = SAMLProvider.objects.create(
            name=generate_id(),
            acs_url=f"http://{self.host}:9009/saml/acs",
            audience="authentik-e2e",
            issuer="authentik-e2e",
            sp_binding=SAMLBindings.POST,
            authorization_flow=authorization_flow,
            signing_kp=create_test_cert(),
        )
        provider.property_mappings.set(SAMLPropertyMapping.objects.all())
        provider.save()
        Application.objects.create(
            name="SAML",
            slug=generate_id(),
            provider=provider,
        )
        self.setup_client(provider, True, SP_ROOT_URL=f"http://{self.host}:9009")
    
        self.driver.get(self.live_server_url)
        login_window = self.driver.current_window_handle
        self.driver.switch_to.new_window("tab")
        client_window = self.driver.current_window_handle
        # We need to access the SP on the same host as the IdP for SameSite cookies
        self.driver.get(f"http://{self.host}:9009")
        self.driver.switch_to.new_window("tab")
        client_window = self.driver.current_window_handle
        # We need to access the SP on the same host as the IdP for SameSite cookies
        self.driver.get(f"http://{self.host}:9009")
        self.driver.switch_to.new_window("tab")
        client_window = self.driver.current_window_handle
        # We need to access the SP on the same host as the IdP for SameSite cookies
        self.driver.get(f"http://{self.host}:9009")
        self.driver.switch_to.new_window("tab")
        client_window = self.driver.current_window_handle
        # We need to access the SP on the same host as the IdP for SameSite cookies
        self.driver.get(f"http://{self.host}:9009")
        self.driver.switch_to.new_window("tab")
        client_window = self.driver.current_window_handle
        # We need to access the SP on the same host as the IdP for SameSite cookies
        self.driver.get(f"http://{self.host}:9009")
    
        self.driver.switch_to.window(login_window)
        self.login()
        self.driver.switch_to.window(client_window)
    
>       self.wait_for_url(f"http://{self.host}:9009/")

tests/e2e/test_provider_saml.py:590: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <tests.e2e.test_provider_saml.TestProviderSAML testMethod=test_sp_initiated_implicit_post_buffer>
desired_url = 'http://10.1.0.138:9009/'

    def wait_for_url(self, desired_url):
        """Wait until URL is `desired_url`."""
>       self.wait.until(
            lambda driver: driver.current_url == desired_url,
            f"URL {self.driver.current_url} doesn't match expected URL {desired_url}",
        )

tests/e2e/utils.py:211: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <selenium.webdriver.support.wait.WebDriverWait (session="88da406f7c495b8edbfd3eb9aa1bd4d6")>
method = <function SeleniumTestCase.wait_for_url.<locals>.<lambda> at 0x7fa44191f560>
message = "URL http://10.1.0.138:32821/policy/buffer?af_bf_id=34b460c5-92a1-41d2-bf31-0b0bdbf82d48 doesn't match expected URL http://10.1.0.138:9009/"

    def until(self, method: Callable[[D], Union[Literal[False], T]], message: str = "") -> T:
        """Wait until the method returns a value that is not False.
    
        Calls the method provided with the driver as an argument until the
        return value does not evaluate to ``False``.
    
        Parameters:
        -----------
        method: callable(WebDriver)
            - A callable object that takes a WebDriver instance as an argument.
    
        message: str
            - Optional message for :exc:`TimeoutException`
    
        Return:
        -------
        object: T
            - The result of the last call to `method`
    
        Raises:
        -------
        TimeoutException
            - If 'method' does not return a truthy value within the WebDriverWait
            object's timeout
    
        Example:
        --------
        >>> from selenium.webdriver.common.by import By
        >>> from selenium.webdriver.support.ui import WebDriverWait
        >>> from selenium.webdriver.support import expected_conditions as EC
    
        # Wait until an element is visible on the page
        >>> wait = WebDriverWait(driver, 10)
        >>> element = wait.until(EC.visibility_of_element_located((By.ID, "exampleId")))
        >>> print(element.text)
        """
        screen = None
        stacktrace = None
    
        end_time = time.monotonic() + self._timeout
        while True:
            try:
                value = method(self._driver)
                if value:
                    return value
            except self._ignored_exceptions as exc:
                screen = getattr(exc, "screen", None)
                stacktrace = getattr(exc, "stacktrace", None)
            if time.monotonic() > end_time:
                break
            time.sleep(self._poll)
>       raise TimeoutException(message, screen, stacktrace)
E       selenium.common.exceptions.TimeoutException: Message: URL http://10.1.0.138:32821/policy/buffer?af_bf_id=34b460c5-92a1-41d2-bf31-0b0bdbf82d48 doesn't match expected URL http://10.1.0.138:9009/

.venv/lib/python3.13.../webdriver/support/wait.py:146: TimeoutException

During handling of the above exception, another exception occurred:

self = <unittest.case._Outcome object at 0x7fa4427b9810>
test_case = <tests.e2e.test_provider_saml.TestProviderSAML testMethod=test_sp_initiated_implicit_post_buffer>
subTest = False

    @contextlib.contextmanager
    def testPartExecutor(self, test_case, subTest=False):
        old_success = self.success
        self.success = True
        try:
>           yield

.../hostedtoolcache/Python/3.13.7........./x64/lib/python3.13/unittest/case.py:58: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <tests.e2e.test_provider_saml.TestProviderSAML testMethod=test_sp_initiated_implicit_post_buffer>
result = <TestCaseFunction test_sp_initiated_implicit_post_buffer>

    def run(self, result=None):
        if result is None:
            result = self.defaultTestResult()
            startTestRun = getattr(result, 'startTestRun', None)
            stopTestRun = getattr(result, 'stopTestRun', None)
            if startTestRun is not None:
                startTestRun()
        else:
            stopTestRun = None
    
        result.startTest(self)
        try:
            testMethod = getattr(self, self._testMethodName)
            if (getattr(self.__class__, "__unittest_skip__", False) or
                getattr(testMethod, "__unittest_skip__", False)):
                # If the class or method was skipped.
                skip_why = (getattr(self.__class__, '__unittest_skip_why__', '')
                            or getattr(testMethod, '__unittest_skip_why__', ''))
                _addSkip(result, self, skip_why)
                return result
    
            expecting_failure = (
                getattr(self, "__unittest_expecting_failure__", False) or
                getattr(testMethod, "__unittest_expecting_failure__", False)
            )
            outcome = _Outcome(result)
            start_time = time.perf_counter()
            try:
                self._outcome = outcome
    
                with outcome.testPartExecutor(self):
                    self._callSetUp()
                if outcome.success:
                    outcome.expecting_failure = expecting_failure
                    with outcome.testPartExecutor(self):
>                       self._callTestMethod(testMethod)

.../hostedtoolcache/Python/3.13.7........./x64/lib/python3.13/unittest/case.py:651: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <tests.e2e.test_provider_saml.TestProviderSAML testMethod=test_sp_initiated_implicit_post_buffer>
method = <bound method TestProviderSAML.test_sp_initiated_implicit_post_buffer of <tests.e2e.test_provider_saml.TestProviderSAML testMethod=test_sp_initiated_implicit_post_buffer>>

    def _callTestMethod(self, method):
>       if method() is not None:

.../hostedtoolcache/Python/3.13.7........./x64/lib/python3.13/unittest/case.py:606: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <tests.e2e.test_provider_saml.TestProviderSAML testMethod=test_sp_initiated_implicit_post_buffer>
args = (), kwargs = {}

    @wraps(func)
    def wrapper(self: TransactionTestCase, *args, **kwargs):
        """Run test again if we're below max_retries, including tearDown and
        setUp. Otherwise raise the error"""
        nonlocal count
        try:
            return func(self, *args, **kwargs)
    
        except tuple(exceptions) as exc:
            count += 1
            if count > max_retires:
                logger.debug("Exceeded retry count", exc=exc, test=self)
    
                raise exc
            logger.debug("Retrying on error", exc=exc, test=self)
            self.tearDown()
            self._post_teardown()
            self._pre_setup()
            self.setUp()
>           return wrapper(self, *args, **kwargs)

tests/e2e/utils.py:337: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <tests.e2e.test_provider_saml.TestProviderSAML testMethod=test_sp_initiated_implicit_post_buffer>
args = (), kwargs = {}

    @wraps(func)
    def wrapper(self: TransactionTestCase, *args, **kwargs):
        """Run test again if we're below max_retries, including tearDown and
        setUp. Otherwise raise the error"""
        nonlocal count
        try:
            return func(self, *args, **kwargs)
    
        except tuple(exceptions) as exc:
            count += 1
            if count > max_retires:
                logger.debug("Exceeded retry count", exc=exc, test=self)
    
                raise exc
            logger.debug("Retrying on error", exc=exc, test=self)
            self.tearDown()
            self._post_teardown()
            self._pre_setup()
            self.setUp()
>           return wrapper(self, *args, **kwargs)

tests/e2e/utils.py:337: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <tests.e2e.test_provider_saml.TestProviderSAML testMethod=test_sp_initiated_implicit_post_buffer>
args = (), kwargs = {}

    @wraps(func)
    def wrapper(self: TransactionTestCase, *args, **kwargs):
        """Run test again if we're below max_retries, including tearDown and
        setUp. Otherwise raise the error"""
        nonlocal count
        try:
            return func(self, *args, **kwargs)
    
        except tuple(exceptions) as exc:
            count += 1
            if count > max_retires:
                logger.debug("Exceeded retry count", exc=exc, test=self)
    
>               raise exc

tests/e2e/utils.py:331: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <tests.e2e.test_provider_saml.TestProviderSAML testMethod=test_sp_initiated_implicit_post_buffer>
args = (), kwargs = {}

    @wraps(func)
    def wrapper(self: TransactionTestCase, *args, **kwargs):
        """Run test again if we're below max_retries, including tearDown and
        setUp. Otherwise raise the error"""
        nonlocal count
        try:
>           return func(self, *args, **kwargs)

tests/e2e/utils.py:324: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

args = (<tests.e2e.test_provider_saml.TestProviderSAML testMethod=test_sp_initiated_implicit_post_buffer>,)
kwargs = {}, file = 'default/flow-default-invalidation-flow.yaml'
content = 'version: 1\nmetadata:\n  name: Default - Invalidation flow\nentries:\n- attrs:\n    designation: invalidation\n    na...0\n    stage: !KeyOf default-invalidation-logout\n    target: !KeyOf flow\n  model: authentik_flows.flowstagebinding\n'

    @wraps(func)
    def wrapper(*args, **kwargs):
        for file in files:
            content = BlueprintInstance(path=file).retrieve()
            Importer.from_string(content).apply()
>       return func(*args, **kwargs)

.../blueprints/tests/__init__.py:25: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

args = (<tests.e2e.test_provider_saml.TestProviderSAML testMethod=test_sp_initiated_implicit_post_buffer>,)
kwargs = {}
file = 'default/flow-default-provider-authorization-implicit-consent.yaml'
content = 'version: 1\nmetadata:\n  name: Default - Provider authorization flow (implicit consent)\nentries:\n- attrs:\n    desi...henticated\n  identifiers:\n    slug: default-provider-authorization-implicit-consent\n  model: authentik_flows.flow\n'

    @wraps(func)
    def wrapper(*args, **kwargs):
        for file in files:
            content = BlueprintInstance(path=file).retrieve()
            Importer.from_string(content).apply()
>       return func(*args, **kwargs)

.../blueprints/tests/__init__.py:25: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

args = (<tests.e2e.test_provider_saml.TestProviderSAML testMethod=test_sp_initiated_implicit_post_buffer>,)
kwargs = {}, file = 'system/providers-saml.yaml'
content = 'version: 1\nmetadata:\n  labels:\n    blueprints.goauthentik.io/system: "true"\n  name: System - SAML Provider - Mapp...rosoft..../identity/claims/windowsaccountname"\n      expression: |\n        return request.user.username\n'

    @wraps(func)
    def wrapper(*args, **kwargs):
        for file in files:
            content = BlueprintInstance(path=file).retrieve()
            Importer.from_string(content).apply()
>       return func(*args, **kwargs)

.../blueprints/tests/__init__.py:25: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

args = (<tests.e2e.test_provider_saml.TestProviderSAML testMethod=test_sp_initiated_implicit_post_buffer>,)
kwargs = {}, config = <AuthentikCryptoConfig: authentik_crypto>

    @wraps(func)
    def wrapper(*args, **kwargs):
        config = apps.get_app_config(app_name)
        if isinstance(config, ManagedAppConfig):
            config._on_startup_callback(None)
>       return func(*args, **kwargs)

.../blueprints/tests/__init__.py:43: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

args = (<tests.e2e.test_provider_saml.TestProviderSAML testMethod=test_sp_initiated_implicit_post_buffer>,)
kwargs = {}, tenant = <Tenant: Tenant Default>

    @wraps(func)
    def wrapper(*args, **kwargs):
        tenant = get_current_tenant()
        tenant.flags[flag().key] = value
        tenant.save()
>       return func(*args, **kwargs)

authentik/tenants/flags.py:54: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <tests.e2e.test_provider_saml.TestProviderSAML testMethod=test_sp_initiated_implicit_post_buffer>

    @retry()
    @apply_blueprint(
        "default/flow-default-authentication-flow.yaml",
        "default/flow-default-invalidation-flow.yaml",
    )
    @apply_blueprint(
        "default/flow-default-provider-authorization-implicit-consent.yaml",
    )
    @apply_blueprint(
        "system/providers-saml.yaml",
    )
    @reconcile_app("authentik_crypto")
    @patch_flag(BufferedPolicyAccessViewFlag, True)
    def test_sp_initiated_implicit_post_buffer(self):
        """test SAML Provider flow SP-initiated flow (implicit consent)"""
        # Bootstrap all needed objects
        authorization_flow = Flow.objects.get(
            slug="default-provider-authorization-implicit-consent"
        )
        provider: SAMLProvider = SAMLProvider.objects.create(
            name=generate_id(),
            acs_url=f"http://{self.host}:9009/saml/acs",
            audience="authentik-e2e",
            issuer="authentik-e2e",
            sp_binding=SAMLBindings.POST,
            authorization_flow=authorization_flow,
            signing_kp=create_test_cert(),
        )
        provider.property_mappings.set(SAMLPropertyMapping.objects.all())
        provider.save()
        Application.objects.create(
            name="SAML",
            slug=generate_id(),
            provider=provider,
        )
        self.setup_client(provider, True, SP_ROOT_URL=f"http://{self.host}:9009")
    
        self.driver.get(self.live_server_url)
        login_window = self.driver.current_window_handle
        self.driver.switch_to.new_window("tab")
        client_window = self.driver.current_window_handle
        # We need to access the SP on the same host as the IdP for SameSite cookies
        self.driver.get(f"http://{self.host}:9009")
        self.driver.switch_to.new_window("tab")
        client_window = self.driver.current_window_handle
        # We need to access the SP on the same host as the IdP for SameSite cookies
        self.driver.get(f"http://{self.host}:9009")
        self.driver.switch_to.new_window("tab")
        client_window = self.driver.current_window_handle
        # We need to access the SP on the same host as the IdP for SameSite cookies
        self.driver.get(f"http://{self.host}:9009")
        self.driver.switch_to.new_window("tab")
        client_window = self.driver.current_window_handle
        # We need to access the SP on the same host as the IdP for SameSite cookies
        self.driver.get(f"http://{self.host}:9009")
        self.driver.switch_to.new_window("tab")
        client_window = self.driver.current_window_handle
        # We need to access the SP on the same host as the IdP for SameSite cookies
        self.driver.get(f"http://{self.host}:9009")
    
        self.driver.switch_to.window(login_window)
        self.login()
        self.driver.switch_to.window(client_window)
    
>       self.wait_for_url(f"http://{self.host}:9009/")

tests/e2e/test_provider_saml.py:590: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <tests.e2e.test_provider_saml.TestProviderSAML testMethod=test_sp_initiated_implicit_post_buffer>
desired_url = 'http://10.1.0.138:9009/'

    def wait_for_url(self, desired_url):
        """Wait until URL is `desired_url`."""
>       self.wait.until(
            lambda driver: driver.current_url == desired_url,
            f"URL {self.driver.current_url} doesn't match expected URL {desired_url}",
        )

tests/e2e/utils.py:211: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <selenium.webdriver.support.wait.WebDriverWait (session="91b323dffa45c11393d4b1c789f3b76f")>
method = <function SeleniumTestCase.wait_for_url.<locals>.<lambda> at 0x7fa4417e53a0>
message = "URL http://10.1.0.138:32821/policy/buffer?af_bf_id=67d282c4-fe99-4ef6-984c-4f028a1c6b09 doesn't match expected URL http://10.1.0.138:9009/"

    def until(self, method: Callable[[D], Union[Literal[False], T]], message: str = "") -> T:
        """Wait until the method returns a value that is not False.
    
        Calls the method provided with the driver as an argument until the
        return value does not evaluate to ``False``.
    
        Parameters:
        -----------
        method: callable(WebDriver)
            - A callable object that takes a WebDriver instance as an argument.
    
        message: str
            - Optional message for :exc:`TimeoutException`
    
        Return:
        -------
        object: T
            - The result of the last call to `method`
    
        Raises:
        -------
        TimeoutException
            - If 'method' does not return a truthy value within the WebDriverWait
            object's timeout
    
        Example:
        --------
        >>> from selenium.webdriver.common.by import By
        >>> from selenium.webdriver.support.ui import WebDriverWait
        >>> from selenium.webdriver.support import expected_conditions as EC
    
        # Wait until an element is visible on the page
        >>> wait = WebDriverWait(driver, 10)
        >>> element = wait.until(EC.visibility_of_element_located((By.ID, "exampleId")))
        >>> print(element.text)
        """
        screen = None
        stacktrace = None
    
        end_time = time.monotonic() + self._timeout
        while True:
            try:
                value = method(self._driver)
                if value:
                    return value
            except self._ignored_exceptions as exc:
                screen = getattr(exc, "screen", None)
                stacktrace = getattr(exc, "stacktrace", None)
            if time.monotonic() > end_time:
                break
            time.sleep(self._poll)
>       raise TimeoutException(message, screen, stacktrace)
E       selenium.common.exceptions.TimeoutException: Message: URL http://10.1.0.138:32821/policy/buffer?af_bf_id=67d282c4-fe99-4ef6-984c-4f028a1c6b09 doesn't match expected URL http://10.1.0.138:9009/

.venv/lib/python3.13.../webdriver/support/wait.py:146: TimeoutException
View the full list of 3 ❄️ flaky test(s)
authentik.tenants.tests.test_api.TestAPI::test_no_api_key_configured

Flake rate in main: 100.00% (Passed 0 times, Failed 51 times)

Stack Traces | 11.4s run time
self = <DatabaseWrapper vendor='postgresql' alias='default'>

    def _commit(self):
        if self.connection is not None:
            with debug_transaction(self, "COMMIT"), self.wrap_database_errors:
>               return self.connection.commit()

.venv/lib/python3.13.../backends/base/base.py:303: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <psycopg.Connection [BAD] at 0x7f47d4a47f20>

    def commit(self) -> None:
        """Commit any pending transaction to the database."""
        with self.lock:
>           self.wait(self._commit_gen())

.venv/lib/python3.13............/site-packages/psycopg/connection.py:262: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <psycopg.Connection [BAD] at 0x7f47d4a47f20>
gen = <generator object BaseConnection._commit_gen at 0x7f47d4534880>
interval = 0.1

    def wait(self, gen: PQGen[RV], interval: float | None = _WAIT_INTERVAL) -> RV:
        """
        Consume a generator operating on the connection.
    
        The function must be used on generators that don't change connection
        fd (i.e. not on connect and reset).
        """
        try:
>           return waiting.wait(gen, self.pgconn.socket, interval=interval)

.venv/lib/python3.13............/site-packages/psycopg/connection.py:414: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

>   ???

psycopg_c/_psycopg/waiting.pyx:213: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <psycopg.Connection [BAD] at 0x7f47d4a47f20>

    def _commit_gen(self) -> PQGen[None]:
        """Generator implementing `Connection.commit()`."""
        if self._num_transactions:
            raise e.ProgrammingError(
                "Explicit commit() forbidden within a Transaction "
                "context. (Transaction will be automatically committed "
                "on successful exit from context.)"
            )
        if self._tpc:
            raise e.ProgrammingError(
                "commit() cannot be used during a two-phase transaction"
            )
        if self.pgconn.transaction_status == IDLE:
            return
    
>       yield from self._exec_command(b"COMMIT")

.venv/lib/python3.13............/site-packages/psycopg/_connection_base.py:580: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <psycopg.Connection [BAD] at 0x7f47d4a47f20>, command = b'COMMIT'
result_format = <Format.TEXT: 0>

    def _exec_command(
        self, command: Query, result_format: pq.Format = TEXT
    ) -> PQGen[PGresult | None]:
        """
        Generator to send a command and receive the result to the backend.
    
        Only used to implement internal commands such as "commit", with eventual
        arguments bound client-side. The cursor can do more complex stuff.
        """
        self._check_connection_ok()
    
        if isinstance(command, str):
            command = command.encode(self.pgconn._encoding)
        elif isinstance(command, Composable):
            command = command.as_bytes(self)
    
        if self._pipeline:
            cmd = partial(
                self.pgconn.send_query_params,
                command,
                None,
                result_format=result_format,
            )
            self._pipeline.command_queue.append(cmd)
            self._pipeline.result_queue.append(None)
            return None
    
        # Unless needed, use the simple query protocol, e.g. to interact with
        # pgbouncer. In pipeline mode we always use the advanced query protocol
        # instead, see #350
        if result_format == TEXT:
            self.pgconn.send_query(command)
        else:
            self.pgconn.send_query_params(command, None, result_format=result_format)
    
        result: PGresult = (yield from generators.execute(self.pgconn))[-1]
        if result.status != COMMAND_OK and result.status != TUPLES_OK:
            if result.status == FATAL_ERROR:
>               raise e.error_from_result(result, encoding=self.pgconn._encoding)
E               psycopg.errors.ForeignKeyViolation: insert or update on table "authentik_core_token" violates foreign key constraint "authentik_core_token_user_id_479d5b79_fk_authentik_core_user_id"
E               DETAIL:  Key (user_id)=(2) is not present in table "authentik_core_user".

.venv/lib/python3.13............/site-packages/psycopg/_connection_base.py:478: ForeignKeyViolation

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

self = <unittest.case._Outcome object at 0x7f47e9612c80>
test_case = <authentik.tenants.tests.test_api.TestAPI testMethod=test_no_api_key_configured>
subTest = False

    @contextlib.contextmanager
    def testPartExecutor(self, test_case, subTest=False):
        old_success = self.success
        self.success = True
        try:
>           yield

.../hostedtoolcache/Python/3.13.7........./x64/lib/python3.13/unittest/case.py:58: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <authentik.tenants.tests.test_api.TestAPI testMethod=test_no_api_key_configured>
result = <TestCaseFunction test_no_api_key_configured>

    def run(self, result=None):
        if result is None:
            result = self.defaultTestResult()
            startTestRun = getattr(result, 'startTestRun', None)
            stopTestRun = getattr(result, 'stopTestRun', None)
            if startTestRun is not None:
                startTestRun()
        else:
            stopTestRun = None
    
        result.startTest(self)
        try:
            testMethod = getattr(self, self._testMethodName)
            if (getattr(self.__class__, "__unittest_skip__", False) or
                getattr(testMethod, "__unittest_skip__", False)):
                # If the class or method was skipped.
                skip_why = (getattr(self.__class__, '__unittest_skip_why__', '')
                            or getattr(testMethod, '__unittest_skip_why__', ''))
                _addSkip(result, self, skip_why)
                return result
    
            expecting_failure = (
                getattr(self, "__unittest_expecting_failure__", False) or
                getattr(testMethod, "__unittest_expecting_failure__", False)
            )
            outcome = _Outcome(result)
            start_time = time.perf_counter()
            try:
                self._outcome = outcome
    
                with outcome.testPartExecutor(self):
>                   self._callSetUp()

.../hostedtoolcache/Python/3.13.7........./x64/lib/python3.13/unittest/case.py:647: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <authentik.tenants.tests.test_api.TestAPI testMethod=test_no_api_key_configured>

    def _callSetUp(self):
>       self.setUp()

.../hostedtoolcache/Python/3.13.7........./x64/lib/python3.13/unittest/case.py:603: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <authentik.tenants.tests.test_api.TestAPI testMethod=test_no_api_key_configured>

    def setUp(self):
        with schema_context(get_public_schema_name()):
>           Tenant.objects.update_or_create(
                defaults={"name": "Template", "ready": False},
                schema_name=get_tenant_base_schema(),
            )

.../tenants/tests/utils.py:24: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <django.db.models.manager.Manager object at 0x7f47e8ac5a50>, args = ()
kwargs = {'defaults': {'name': 'Template', 'ready': False}, 'schema_name': 'template'}

    @wraps(method)
    def manager_method(self, *args, **kwargs):
>       return getattr(self.get_queryset(), name)(*args, **kwargs)

.venv/lib/python3.13.../db/models/manager.py:87: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <QuerySet [<Tenant: Tenant Default>]>
defaults = {'name': 'Template', 'ready': False}
create_defaults = {'name': 'Template', 'ready': False}
kwargs = {'schema_name': 'template'}
update_defaults = {'name': 'Template', 'ready': False}
obj = <Tenant: Tenant Template>, created = True

    def update_or_create(self, defaults=None, create_defaults=None, **kwargs):
        """
        Look up an object with the given kwargs, updating one with defaults
        if it exists, otherwise create a new one. Optionally, an object can
        be created with different values than defaults by using
        create_defaults.
        Return a tuple (object, created), where created is a boolean
        specifying whether an object was created.
        """
        update_defaults = defaults or {}
        if create_defaults is None:
            create_defaults = update_defaults
    
        self._for_write = True
>       with transaction.atomic(using=self.db):

.venv/lib/python3.13.../db/models/query.py:985: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <django.db.transaction.Atomic object at 0x7f47e9610600>, exc_type = None
exc_value = None, traceback = None

    def __exit__(self, exc_type, exc_value, traceback):
        connection = get_connection(self.using)
    
        if connection.in_atomic_block:
            connection.atomic_blocks.pop()
    
        if connection.savepoint_ids:
            sid = connection.savepoint_ids.pop()
        else:
            # Prematurely unset this flag to allow using commit or rollback.
            connection.in_atomic_block = False
    
        try:
            if connection.closed_in_transaction:
                # The database will perform a rollback by itself.
                # Wait until we exit the outermost block.
                pass
    
            elif exc_type is None and not connection.needs_rollback:
                if connection.in_atomic_block:
                    # Release savepoint if there is one
                    if sid is not None:
                        try:
                            connection.savepoint_commit(sid)
                        except DatabaseError:
                            try:
                                connection.savepoint_rollback(sid)
                                # The savepoint won't be reused. Release it to
                                # minimize overhead for the database server.
                                connection.savepoint_commit(sid)
                            except Error:
                                # If rolling back to a savepoint fails, mark for
                                # rollback at a higher level and avoid shadowing
                                # the original exception.
                                connection.needs_rollback = True
                            raise
                else:
                    # Commit transaction
                    try:
>                       connection.commit()

.venv/lib/python3.13.../django/db/transaction.py:263: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

args = (<DatabaseWrapper vendor='postgresql' alias='default'>,), kwargs = {}

    @wraps(func)
    def inner(*args, **kwargs):
        # Detect a running event loop in this thread.
        try:
            get_running_loop()
        except RuntimeError:
            pass
        else:
            if not os.environ.get("DJANGO_ALLOW_ASYNC_UNSAFE"):
                raise SynchronousOnlyOperation(message)
        # Pass onward.
>       return func(*args, **kwargs)

.venv/lib/python3.13.../django/utils/asyncio.py:26: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DatabaseWrapper vendor='postgresql' alias='default'>

    @async_unsafe
    def commit(self):
        """Commit a transaction and reset the dirty flag."""
        self.validate_thread_sharing()
        self.validate_no_atomic_block()
>       self._commit()

.venv/lib/python3.13.../backends/base/base.py:327: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DatabaseWrapper vendor='postgresql' alias='default'>

    def _commit(self):
        if self.connection is not None:
>           with debug_transaction(self, "COMMIT"), self.wrap_database_errors:

.venv/lib/python3.13.../backends/base/base.py:302: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <django.db.utils.DatabaseErrorWrapper object at 0x7f47f519cec0>
exc_type = <class 'psycopg.errors.ForeignKeyViolation'>
exc_value = ForeignKeyViolation('insert or update on table "authentik_core_token" violates foreign key constraint "authentik_core_...ser_id_479d5b79_fk_authentik_core_user_id"\nDETAIL:  Key (user_id)=(2) is not present in table "authentik_core_user".')
traceback = <traceback object at 0x7f47f274e480>

    def __exit__(self, exc_type, exc_value, traceback):
        if exc_type is None:
            return
        for dj_exc_type in (
            DataError,
            OperationalError,
            IntegrityError,
            InternalError,
            ProgrammingError,
            NotSupportedError,
            DatabaseError,
            InterfaceError,
            Error,
        ):
            db_exc_type = getattr(self.wrapper.Database, dj_exc_type.__name__)
            if issubclass(exc_type, db_exc_type):
                dj_exc_value = dj_exc_type(*exc_value.args)
                # Only set the 'errors_occurred' flag for errors that may make
                # the connection unusable.
                if dj_exc_type not in (DataError, IntegrityError):
                    self.wrapper.errors_occurred = True
>               raise dj_exc_value.with_traceback(traceback) from exc_value

.venv/lib/python3.13.../django/db/utils.py:91: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DatabaseWrapper vendor='postgresql' alias='default'>

    def _commit(self):
        if self.connection is not None:
            with debug_transaction(self, "COMMIT"), self.wrap_database_errors:
>               return self.connection.commit()

.venv/lib/python3.13.../backends/base/base.py:303: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <psycopg.Connection [BAD] at 0x7f47d4a47f20>

    def commit(self) -> None:
        """Commit any pending transaction to the database."""
        with self.lock:
>           self.wait(self._commit_gen())

.venv/lib/python3.13............/site-packages/psycopg/connection.py:262: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <psycopg.Connection [BAD] at 0x7f47d4a47f20>
gen = <generator object BaseConnection._commit_gen at 0x7f47d4534880>
interval = 0.1

    def wait(self, gen: PQGen[RV], interval: float | None = _WAIT_INTERVAL) -> RV:
        """
        Consume a generator operating on the connection.
    
        The function must be used on generators that don't change connection
        fd (i.e. not on connect and reset).
        """
        try:
>           return waiting.wait(gen, self.pgconn.socket, interval=interval)

.venv/lib/python3.13............/site-packages/psycopg/connection.py:414: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

>   ???

psycopg_c/_psycopg/waiting.pyx:213: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <psycopg.Connection [BAD] at 0x7f47d4a47f20>

    def _commit_gen(self) -> PQGen[None]:
        """Generator implementing `Connection.commit()`."""
        if self._num_transactions:
            raise e.ProgrammingError(
                "Explicit commit() forbidden within a Transaction "
                "context. (Transaction will be automatically committed "
                "on successful exit from context.)"
            )
        if self._tpc:
            raise e.ProgrammingError(
                "commit() cannot be used during a two-phase transaction"
            )
        if self.pgconn.transaction_status == IDLE:
            return
    
>       yield from self._exec_command(b"COMMIT")

.venv/lib/python3.13............/site-packages/psycopg/_connection_base.py:580: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <psycopg.Connection [BAD] at 0x7f47d4a47f20>, command = b'COMMIT'
result_format = <Format.TEXT: 0>

    def _exec_command(
        self, command: Query, result_format: pq.Format = TEXT
    ) -> PQGen[PGresult | None]:
        """
        Generator to send a command and receive the result to the backend.
    
        Only used to implement internal commands such as "commit", with eventual
        arguments bound client-side. The cursor can do more complex stuff.
        """
        self._check_connection_ok()
    
        if isinstance(command, str):
            command = command.encode(self.pgconn._encoding)
        elif isinstance(command, Composable):
            command = command.as_bytes(self)
    
        if self._pipeline:
            cmd = partial(
                self.pgconn.send_query_params,
                command,
                None,
                result_format=result_format,
            )
            self._pipeline.command_queue.append(cmd)
            self._pipeline.result_queue.append(None)
            return None
    
        # Unless needed, use the simple query protocol, e.g. to interact with
        # pgbouncer. In pipeline mode we always use the advanced query protocol
        # instead, see #350
        if result_format == TEXT:
            self.pgconn.send_query(command)
        else:
            self.pgconn.send_query_params(command, None, result_format=result_format)
    
        result: PGresult = (yield from generators.execute(self.pgconn))[-1]
        if result.status != COMMAND_OK and result.status != TUPLES_OK:
            if result.status == FATAL_ERROR:
>               raise e.error_from_result(result, encoding=self.pgconn._encoding)
E               django.db.utils.IntegrityError: insert or update on table "authentik_core_token" violates foreign key constraint "authentik_core_token_user_id_479d5b79_fk_authentik_core_user_id"
E               DETAIL:  Key (user_id)=(2) is not present in table "authentik_core_user".

.venv/lib/python3.13............/site-packages/psycopg/_connection_base.py:478: IntegrityError
authentik.tenants.tests.test_api.TestAPI::test_tenant_create_delete

Flake rate in main: 100.00% (Passed 0 times, Failed 51 times)

Stack Traces | 11.6s run time
self = <DatabaseWrapper vendor='postgresql' alias='default'>

    def _commit(self):
        if self.connection is not None:
            with debug_transaction(self, "COMMIT"), self.wrap_database_errors:
>               return self.connection.commit()

.venv/lib/python3.13.../backends/base/base.py:303: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <psycopg.Connection [BAD] at 0x7f47df682c60>

    def commit(self) -> None:
        """Commit any pending transaction to the database."""
        with self.lock:
>           self.wait(self._commit_gen())

.venv/lib/python3.13............/site-packages/psycopg/connection.py:262: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <psycopg.Connection [BAD] at 0x7f47df682c60>
gen = <generator object BaseConnection._commit_gen at 0x7f47d4537280>
interval = 0.1

    def wait(self, gen: PQGen[RV], interval: float | None = _WAIT_INTERVAL) -> RV:
        """
        Consume a generator operating on the connection.
    
        The function must be used on generators that don't change connection
        fd (i.e. not on connect and reset).
        """
        try:
>           return waiting.wait(gen, self.pgconn.socket, interval=interval)

.venv/lib/python3.13............/site-packages/psycopg/connection.py:414: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

>   ???

psycopg_c/_psycopg/waiting.pyx:213: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <psycopg.Connection [BAD] at 0x7f47df682c60>

    def _commit_gen(self) -> PQGen[None]:
        """Generator implementing `Connection.commit()`."""
        if self._num_transactions:
            raise e.ProgrammingError(
                "Explicit commit() forbidden within a Transaction "
                "context. (Transaction will be automatically committed "
                "on successful exit from context.)"
            )
        if self._tpc:
            raise e.ProgrammingError(
                "commit() cannot be used during a two-phase transaction"
            )
        if self.pgconn.transaction_status == IDLE:
            return
    
>       yield from self._exec_command(b"COMMIT")

.venv/lib/python3.13............/site-packages/psycopg/_connection_base.py:580: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <psycopg.Connection [BAD] at 0x7f47df682c60>, command = b'COMMIT'
result_format = <Format.TEXT: 0>

    def _exec_command(
        self, command: Query, result_format: pq.Format = TEXT
    ) -> PQGen[PGresult | None]:
        """
        Generator to send a command and receive the result to the backend.
    
        Only used to implement internal commands such as "commit", with eventual
        arguments bound client-side. The cursor can do more complex stuff.
        """
        self._check_connection_ok()
    
        if isinstance(command, str):
            command = command.encode(self.pgconn._encoding)
        elif isinstance(command, Composable):
            command = command.as_bytes(self)
    
        if self._pipeline:
            cmd = partial(
                self.pgconn.send_query_params,
                command,
                None,
                result_format=result_format,
            )
            self._pipeline.command_queue.append(cmd)
            self._pipeline.result_queue.append(None)
            return None
    
        # Unless needed, use the simple query protocol, e.g. to interact with
        # pgbouncer. In pipeline mode we always use the advanced query protocol
        # instead, see #350
        if result_format == TEXT:
            self.pgconn.send_query(command)
        else:
            self.pgconn.send_query_params(command, None, result_format=result_format)
    
        result: PGresult = (yield from generators.execute(self.pgconn))[-1]
        if result.status != COMMAND_OK and result.status != TUPLES_OK:
            if result.status == FATAL_ERROR:
>               raise e.error_from_result(result, encoding=self.pgconn._encoding)
E               psycopg.errors.ForeignKeyViolation: insert or update on table "authentik_core_token" violates foreign key constraint "authentik_core_token_user_id_479d5b79_fk_authentik_core_user_id"
E               DETAIL:  Key (user_id)=(2) is not present in table "authentik_core_user".

.venv/lib/python3.13............/site-packages/psycopg/_connection_base.py:478: ForeignKeyViolation

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

self = <unittest.case._Outcome object at 0x7f47e8d7f5b0>
test_case = <authentik.tenants.tests.test_api.TestAPI testMethod=test_tenant_create_delete>
subTest = False

    @contextlib.contextmanager
    def testPartExecutor(self, test_case, subTest=False):
        old_success = self.success
        self.success = True
        try:
>           yield

.../hostedtoolcache/Python/3.13.7........./x64/lib/python3.13/unittest/case.py:58: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <authentik.tenants.tests.test_api.TestAPI testMethod=test_tenant_create_delete>
result = <TestCaseFunction test_tenant_create_delete>

    def run(self, result=None):
        if result is None:
            result = self.defaultTestResult()
            startTestRun = getattr(result, 'startTestRun', None)
            stopTestRun = getattr(result, 'stopTestRun', None)
            if startTestRun is not None:
                startTestRun()
        else:
            stopTestRun = None
    
        result.startTest(self)
        try:
            testMethod = getattr(self, self._testMethodName)
            if (getattr(self.__class__, "__unittest_skip__", False) or
                getattr(testMethod, "__unittest_skip__", False)):
                # If the class or method was skipped.
                skip_why = (getattr(self.__class__, '__unittest_skip_why__', '')
                            or getattr(testMethod, '__unittest_skip_why__', ''))
                _addSkip(result, self, skip_why)
                return result
    
            expecting_failure = (
                getattr(self, "__unittest_expecting_failure__", False) or
                getattr(testMethod, "__unittest_expecting_failure__", False)
            )
            outcome = _Outcome(result)
            start_time = time.perf_counter()
            try:
                self._outcome = outcome
    
                with outcome.testPartExecutor(self):
>                   self._callSetUp()

.../hostedtoolcache/Python/3.13.7........./x64/lib/python3.13/unittest/case.py:647: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <authentik.tenants.tests.test_api.TestAPI testMethod=test_tenant_create_delete>

    def _callSetUp(self):
>       self.setUp()

.../hostedtoolcache/Python/3.13.7........./x64/lib/python3.13/unittest/case.py:603: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <authentik.tenants.tests.test_api.TestAPI testMethod=test_tenant_create_delete>

    def setUp(self):
        with schema_context(get_public_schema_name()):
>           Tenant.objects.update_or_create(
                defaults={"name": "Template", "ready": False},
                schema_name=get_tenant_base_schema(),
            )

.../tenants/tests/utils.py:24: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <django.db.models.manager.Manager object at 0x7f47e8ac5a50>, args = ()
kwargs = {'defaults': {'name': 'Template', 'ready': False}, 'schema_name': 'template'}

    @wraps(method)
    def manager_method(self, *args, **kwargs):
>       return getattr(self.get_queryset(), name)(*args, **kwargs)

.venv/lib/python3.13.../db/models/manager.py:87: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <QuerySet [<Tenant: Tenant Default>]>
defaults = {'name': 'Template', 'ready': False}
create_defaults = {'name': 'Template', 'ready': False}
kwargs = {'schema_name': 'template'}
update_defaults = {'name': 'Template', 'ready': False}
obj = <Tenant: Tenant Template>, created = True

    def update_or_create(self, defaults=None, create_defaults=None, **kwargs):
        """
        Look up an object with the given kwargs, updating one with defaults
        if it exists, otherwise create a new one. Optionally, an object can
        be created with different values than defaults by using
        create_defaults.
        Return a tuple (object, created), where created is a boolean
        specifying whether an object was created.
        """
        update_defaults = defaults or {}
        if create_defaults is None:
            create_defaults = update_defaults
    
        self._for_write = True
>       with transaction.atomic(using=self.db):

.venv/lib/python3.13.../db/models/query.py:985: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <django.db.transaction.Atomic object at 0x7f47e9116eb0>, exc_type = None
exc_value = None, traceback = None

    def __exit__(self, exc_type, exc_value, traceback):
        connection = get_connection(self.using)
    
        if connection.in_atomic_block:
            connection.atomic_blocks.pop()
    
        if connection.savepoint_ids:
            sid = connection.savepoint_ids.pop()
        else:
            # Prematurely unset this flag to allow using commit or rollback.
            connection.in_atomic_block = False
    
        try:
            if connection.closed_in_transaction:
                # The database will perform a rollback by itself.
                # Wait until we exit the outermost block.
                pass
    
            elif exc_type is None and not connection.needs_rollback:
                if connection.in_atomic_block:
                    # Release savepoint if there is one
                    if sid is not None:
                        try:
                            connection.savepoint_commit(sid)
                        except DatabaseError:
                            try:
                                connection.savepoint_rollback(sid)
                                # The savepoint won't be reused. Release it to
                                # minimize overhead for the database server.
                                connection.savepoint_commit(sid)
                            except Error:
                                # If rolling back to a savepoint fails, mark for
                                # rollback at a higher level and avoid shadowing
                                # the original exception.
                                connection.needs_rollback = True
                            raise
                else:
                    # Commit transaction
                    try:
>                       connection.commit()

.venv/lib/python3.13.../django/db/transaction.py:263: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

args = (<DatabaseWrapper vendor='postgresql' alias='default'>,), kwargs = {}

    @wraps(func)
    def inner(*args, **kwargs):
        # Detect a running event loop in this thread.
        try:
            get_running_loop()
        except RuntimeError:
            pass
        else:
            if not os.environ.get("DJANGO_ALLOW_ASYNC_UNSAFE"):
                raise SynchronousOnlyOperation(message)
        # Pass onward.
>       return func(*args, **kwargs)

.venv/lib/python3.13.../django/utils/asyncio.py:26: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DatabaseWrapper vendor='postgresql' alias='default'>

    @async_unsafe
    def commit(self):
        """Commit a transaction and reset the dirty flag."""
        self.validate_thread_sharing()
        self.validate_no_atomic_block()
>       self._commit()

.venv/lib/python3.13.../backends/base/base.py:327: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DatabaseWrapper vendor='postgresql' alias='default'>

    def _commit(self):
        if self.connection is not None:
>           with debug_transaction(self, "COMMIT"), self.wrap_database_errors:

.venv/lib/python3.13.../backends/base/base.py:302: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <django.db.utils.DatabaseErrorWrapper object at 0x7f47f519cec0>
exc_type = <class 'psycopg.errors.ForeignKeyViolation'>
exc_value = ForeignKeyViolation('insert or update on table "authentik_core_token" violates foreign key constraint "authentik_core_...ser_id_479d5b79_fk_authentik_core_user_id"\nDETAIL:  Key (user_id)=(2) is not present in table "authentik_core_user".')
traceback = <traceback object at 0x7f47d4dbb4c0>

    def __exit__(self, exc_type, exc_value, traceback):
        if exc_type is None:
            return
        for dj_exc_type in (
            DataError,
            OperationalError,
            IntegrityError,
            InternalError,
            ProgrammingError,
            NotSupportedError,
            DatabaseError,
            InterfaceError,
            Error,
        ):
            db_exc_type = getattr(self.wrapper.Database, dj_exc_type.__name__)
            if issubclass(exc_type, db_exc_type):
                dj_exc_value = dj_exc_type(*exc_value.args)
                # Only set the 'errors_occurred' flag for errors that may make
                # the connection unusable.
                if dj_exc_type not in (DataError, IntegrityError):
                    self.wrapper.errors_occurred = True
>               raise dj_exc_value.with_traceback(traceback) from exc_value

.venv/lib/python3.13.../django/db/utils.py:91: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DatabaseWrapper vendor='postgresql' alias='default'>

    def _commit(self):
        if self.connection is not None:
            with debug_transaction(self, "COMMIT"), self.wrap_database_errors:
>               return self.connection.commit()

.venv/lib/python3.13.../backends/base/base.py:303: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <psycopg.Connection [BAD] at 0x7f47df682c60>

    def commit(self) -> None:
        """Commit any pending transaction to the database."""
        with self.lock:
>           self.wait(self._commit_gen())

.venv/lib/python3.13............/site-packages/psycopg/connection.py:262: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <psycopg.Connection [BAD] at 0x7f47df682c60>
gen = <generator object BaseConnection._commit_gen at 0x7f47d4537280>
interval = 0.1

    def wait(self, gen: PQGen[RV], interval: float | None = _WAIT_INTERVAL) -> RV:
        """
        Consume a generator operating on the connection.
    
        The function must be used on generators that don't change connection
        fd (i.e. not on connect and reset).
        """
        try:
>           return waiting.wait(gen, self.pgconn.socket, interval=interval)

.venv/lib/python3.13............/site-packages/psycopg/connection.py:414: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

>   ???

psycopg_c/_psycopg/waiting.pyx:213: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <psycopg.Connection [BAD] at 0x7f47df682c60>

    def _commit_gen(self) -> PQGen[None]:
        """Generator implementing `Connection.commit()`."""
        if self._num_transactions:
            raise e.ProgrammingError(
                "Explicit commit() forbidden within a Transaction "
                "context. (Transaction will be automatically committed "
                "on successful exit from context.)"
            )
        if self._tpc:
            raise e.ProgrammingError(
                "commit() cannot be used during a two-phase transaction"
            )
        if self.pgconn.transaction_status == IDLE:
            return
    
>       yield from self._exec_command(b"COMMIT")

.venv/lib/python3.13............/site-packages/psycopg/_connection_base.py:580: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <psycopg.Connection [BAD] at 0x7f47df682c60>, command = b'COMMIT'
result_format = <Format.TEXT: 0>

    def _exec_command(
        self, command: Query, result_format: pq.Format = TEXT
    ) -> PQGen[PGresult | None]:
        """
        Generator to send a command and receive the result to the backend.
    
        Only used to implement internal commands such as "commit", with eventual
        arguments bound client-side. The cursor can do more complex stuff.
        """
        self._check_connection_ok()
    
        if isinstance(command, str):
            command = command.encode(self.pgconn._encoding)
        elif isinstance(command, Composable):
            command = command.as_bytes(self)
    
        if self._pipeline:
            cmd = partial(
                self.pgconn.send_query_params,
                command,
                None,
                result_format=result_format,
            )
            self._pipeline.command_queue.append(cmd)
            self._pipeline.result_queue.append(None)
            return None
    
        # Unless needed, use the simple query protocol, e.g. to interact with
        # pgbouncer. In pipeline mode we always use the advanced query protocol
        # instead, see #350
        if result_format == TEXT:
            self.pgconn.send_query(command)
        else:
            self.pgconn.send_query_params(command, None, result_format=result_format)
    
        result: PGresult = (yield from generators.execute(self.pgconn))[-1]
        if result.status != COMMAND_OK and result.status != TUPLES_OK:
            if result.status == FATAL_ERROR:
>               raise e.error_from_result(result, encoding=self.pgconn._encoding)
E               django.db.utils.IntegrityError: insert or update on table "authentik_core_token" violates foreign key constraint "authentik_core_token_user_id_479d5b79_fk_authentik_core_user_id"
E               DETAIL:  Key (user_id)=(2) is not present in table "authentik_core_user".

.venv/lib/python3.13............/site-packages/psycopg/_connection_base.py:478: IntegrityError
authentik.tenants.tests.test_api.TestAPI::test_unauthenticated

Flake rate in main: 100.00% (Passed 0 times, Failed 51 times)

Stack Traces | 11.4s run time
self = <DatabaseWrapper vendor='postgresql' alias='default'>

    def _commit(self):
        if self.connection is not None:
            with debug_transaction(self, "COMMIT"), self.wrap_database_errors:
>               return self.connection.commit()

.venv/lib/python3.13.../backends/base/base.py:303: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <psycopg.Connection [BAD] at 0x7f47df4372f0>

    def commit(self) -> None:
        """Commit any pending transaction to the database."""
        with self.lock:
>           self.wait(self._commit_gen())

.venv/lib/python3.13............/site-packages/psycopg/connection.py:262: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <psycopg.Connection [BAD] at 0x7f47df4372f0>
gen = <generator object BaseConnection._commit_gen at 0x7f47d452f400>
interval = 0.1

    def wait(self, gen: PQGen[RV], interval: float | None = _WAIT_INTERVAL) -> RV:
        """
        Consume a generator operating on the connection.
    
        The function must be used on generators that don't change connection
        fd (i.e. not on connect and reset).
        """
        try:
>           return waiting.wait(gen, self.pgconn.socket, interval=interval)

.venv/lib/python3.13............/site-packages/psycopg/connection.py:414: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

>   ???

psycopg_c/_psycopg/waiting.pyx:213: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <psycopg.Connection [BAD] at 0x7f47df4372f0>

    def _commit_gen(self) -> PQGen[None]:
        """Generator implementing `Connection.commit()`."""
        if self._num_transactions:
            raise e.ProgrammingError(
                "Explicit commit() forbidden within a Transaction "
                "context. (Transaction will be automatically committed "
                "on successful exit from context.)"
            )
        if self._tpc:
            raise e.ProgrammingError(
                "commit() cannot be used during a two-phase transaction"
            )
        if self.pgconn.transaction_status == IDLE:
            return
    
>       yield from self._exec_command(b"COMMIT")

.venv/lib/python3.13............/site-packages/psycopg/_connection_base.py:580: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <psycopg.Connection [BAD] at 0x7f47df4372f0>, command = b'COMMIT'
result_format = <Format.TEXT: 0>

    def _exec_command(
        self, command: Query, result_format: pq.Format = TEXT
    ) -> PQGen[PGresult | None]:
        """
        Generator to send a command and receive the result to the backend.
    
        Only used to implement internal commands such as "commit", with eventual
        arguments bound client-side. The cursor can do more complex stuff.
        """
        self._check_connection_ok()
    
        if isinstance(command, str):
            command = command.encode(self.pgconn._encoding)
        elif isinstance(command, Composable):
            command = command.as_bytes(self)
    
        if self._pipeline:
            cmd = partial(
                self.pgconn.send_query_params,
                command,
                None,
                result_format=result_format,
            )
            self._pipeline.command_queue.append(cmd)
            self._pipeline.result_queue.append(None)
            return None
    
        # Unless needed, use the simple query protocol, e.g. to interact with
        # pgbouncer. In pipeline mode we always use the advanced query protocol
        # instead, see #350
        if result_format == TEXT:
            self.pgconn.send_query(command)
        else:
            self.pgconn.send_query_params(command, None, result_format=result_format)
    
        result: PGresult = (yield from generators.execute(self.pgconn))[-1]
        if result.status != COMMAND_OK and result.status != TUPLES_OK:
            if result.status == FATAL_ERROR:
>               raise e.error_from_result(result, encoding=self.pgconn._encoding)
E               psycopg.errors.ForeignKeyViolation: insert or update on table "authentik_core_token" violates foreign key constraint "authentik_core_token_user_id_479d5b79_fk_authentik_core_user_id"
E               DETAIL:  Key (user_id)=(2) is not present in table "authentik_core_user".

.venv/lib/python3.13............/site-packages/psycopg/_connection_base.py:478: ForeignKeyViolation

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

self = <unittest.case._Outcome object at 0x7f47e8fbb850>
test_case = <authentik.tenants.tests.test_api.TestAPI testMethod=test_unauthenticated>
subTest = False

    @contextlib.contextmanager
    def testPartExecutor(self, test_case, subTest=False):
        old_success = self.success
        self.success = True
        try:
>           yield

.../hostedtoolcache/Python/3.13.7........./x64/lib/python3.13/unittest/case.py:58: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <authentik.tenants.tests.test_api.TestAPI testMethod=test_unauthenticated>
result = <TestCaseFunction test_unauthenticated>

    def run(self, result=None):
        if result is None:
            result = self.defaultTestResult()
            startTestRun = getattr(result, 'startTestRun', None)
            stopTestRun = getattr(result, 'stopTestRun', None)
            if startTestRun is not None:
                startTestRun()
        else:
            stopTestRun = None
    
        result.startTest(self)
        try:
            testMethod = getattr(self, self._testMethodName)
            if (getattr(self.__class__, "__unittest_skip__", False) or
                getattr(testMethod, "__unittest_skip__", False)):
                # If the class or method was skipped.
                skip_why = (getattr(self.__class__, '__unittest_skip_why__', '')
                            or getattr(testMethod, '__unittest_skip_why__', ''))
                _addSkip(result, self, skip_why)
                return result
    
            expecting_failure = (
                getattr(self, "__unittest_expecting_failure__", False) or
                getattr(testMethod, "__unittest_expecting_failure__", False)
            )
            outcome = _Outcome(result)
            start_time = time.perf_counter()
            try:
                self._outcome = outcome
    
                with outcome.testPartExecutor(self):
>                   self._callSetUp()

.../hostedtoolcache/Python/3.13.7........./x64/lib/python3.13/unittest/case.py:647: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <authentik.tenants.tests.test_api.TestAPI testMethod=test_unauthenticated>

    def _callSetUp(self):
>       self.setUp()

.../hostedtoolcache/Python/3.13.7........./x64/lib/python3.13/unittest/case.py:603: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <authentik.tenants.tests.test_api.TestAPI testMethod=test_unauthenticated>

    def setUp(self):
        with schema_context(get_public_schema_name()):
>           Tenant.objects.update_or_create(
                defaults={"name": "Template", "ready": False},
                schema_name=get_tenant_base_schema(),
            )

.../tenants/tests/utils.py:24: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <django.db.models.manager.Manager object at 0x7f47e8ac5a50>, args = ()
kwargs = {'defaults': {'name': 'Template', 'ready': False}, 'schema_name': 'template'}

    @wraps(method)
    def manager_method(self, *args, **kwargs):
>       return getattr(self.get_queryset(), name)(*args, **kwargs)

.venv/lib/python3.13.../db/models/manager.py:87: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <QuerySet [<Tenant: Tenant Default>]>
defaults = {'name': 'Template', 'ready': False}
create_defaults = {'name': 'Template', 'ready': False}
kwargs = {'schema_name': 'template'}
update_defaults = {'name': 'Template', 'ready': False}
obj = <Tenant: Tenant Template>, created = True

    def update_or_create(self, defaults=None, create_defaults=None, **kwargs):
        """
        Look up an object with the given kwargs, updating one with defaults
        if it exists, otherwise create a new one. Optionally, an object can
        be created with different values than defaults by using
        create_defaults.
        Return a tuple (object, created), where created is a boolean
        specifying whether an object was created.
        """
        update_defaults = defaults or {}
        if create_defaults is None:
            create_defaults = update_defaults
    
        self._for_write = True
>       with transaction.atomic(using=self.db):

.venv/lib/python3.13.../db/models/query.py:985: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <django.db.transaction.Atomic object at 0x7f47eabdfaf0>, exc_type = None
exc_value = None, traceback = None

    def __exit__(self, exc_type, exc_value, traceback):
        connection = get_connection(self.using)
    
        if connection.in_atomic_block:
            connection.atomic_blocks.pop()
    
        if connection.savepoint_ids:
            sid = connection.savepoint_ids.pop()
        else:
            # Prematurely unset this flag to allow using commit or rollback.
            connection.in_atomic_block = False
    
        try:
            if connection.closed_in_transaction:
                # The database will perform a rollback by itself.
                # Wait until we exit the outermost block.
                pass
    
            elif exc_type is None and not connection.needs_rollback:
                if connection.in_atomic_block:
                    # Release savepoint if there is one
                    if sid is not None:
                        try:
                            connection.savepoint_commit(sid)
                        except DatabaseError:
                            try:
                                connection.savepoint_rollback(sid)
                                # The savepoint won't be reused. Release it to
                                # minimize overhead for the database server.
                                connection.savepoint_commit(sid)
                            except Error:
                                # If rolling back to a savepoint fails, mark for
                                # rollback at a higher level and avoid shadowing
                                # the original exception.
                                connection.needs_rollback = True
                            raise
                else:
                    # Commit transaction
                    try:
>                       connection.commit()

.venv/lib/python3.13.../django/db/transaction.py:263: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

args = (<DatabaseWrapper vendor='postgresql' alias='default'>,), kwargs = {}

    @wraps(func)
    def inner(*args, **kwargs):
        # Detect a running event loop in this thread.
        try:
            get_running_loop()
        except RuntimeError:
            pass
        else:
            if not os.environ.get("DJANGO_ALLOW_ASYNC_UNSAFE"):
                raise SynchronousOnlyOperation(message)
        # Pass onward.
>       return func(*args, **kwargs)

.venv/lib/python3.13.../django/utils/asyncio.py:26: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DatabaseWrapper vendor='postgresql' alias='default'>

    @async_unsafe
    def commit(self):
        """Commit a transaction and reset the dirty flag."""
        self.validate_thread_sharing()
        self.validate_no_atomic_block()
>       self._commit()

.venv/lib/python3.13.../backends/base/base.py:327: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DatabaseWrapper vendor='postgresql' alias='default'>

    def _commit(self):
        if self.connection is not None:
>           with debug_transaction(self, "COMMIT"), self.wrap_database_errors:

.venv/lib/python3.13.../backends/base/base.py:302: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <django.db.utils.DatabaseErrorWrapper object at 0x7f47f519cec0>
exc_type = <class 'psycopg.errors.ForeignKeyViolation'>
exc_value = ForeignKeyViolation('insert or update on table "authentik_core_token" violates foreign key constraint "authentik_core_...ser_id_479d5b79_fk_authentik_core_user_id"\nDETAIL:  Key (user_id)=(2) is not present in table "authentik_core_user".')
traceback = <traceback object at 0x7f47dc30c1c0>

    def __exit__(self, exc_type, exc_value, traceback):
        if exc_type is None:
            return
        for dj_exc_type in (
            DataError,
            OperationalError,
            IntegrityError,
            InternalError,
            ProgrammingError,
            NotSupportedError,
            DatabaseError,
            InterfaceError,
            Error,
        ):
            db_exc_type = getattr(self.wrapper.Database, dj_exc_type.__name__)
            if issubclass(exc_type, db_exc_type):
                dj_exc_value = dj_exc_type(*exc_value.args)
                # Only set the 'errors_occurred' flag for errors that may make
                # the connection unusable.
                if dj_exc_type not in (DataError, IntegrityError):
                    self.wrapper.errors_occurred = True
>               raise dj_exc_value.with_traceback(traceback) from exc_value

.venv/lib/python3.13.../django/db/utils.py:91: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DatabaseWrapper vendor='postgresql' alias='default'>

    def _commit(self):
        if self.connection is not None:
            with debug_transaction(self, "COMMIT"), self.wrap_database_errors:
>               return self.connection.commit()

.venv/lib/python3.13.../backends/base/base.py:303: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <psycopg.Connection [BAD] at 0x7f47df4372f0>

    def commit(self) -> None:
        """Commit any pending transaction to the database."""
        with self.lock:
>           self.wait(self._commit_gen())

.venv/lib/python3.13............/site-packages/psycopg/connection.py:262: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <psycopg.Connection [BAD] at 0x7f47df4372f0>
gen = <generator object BaseConnection._commit_gen at 0x7f47d452f400>
interval = 0.1

    def wait(self, gen: PQGen[RV], interval: float | None = _WAIT_INTERVAL) -> RV:
        """
        Consume a generator operating on the connection.
    
        The function must be used on generators that don't change connection
        fd (i.e. not on connect and reset).
        """
        try:
>           return waiting.wait(gen, self.pgconn.socket, interval=interval)

.venv/lib/python3.13............/site-packages/psycopg/connection.py:414: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

>   ???

psycopg_c/_psycopg/waiting.pyx:213: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <psycopg.Connection [BAD] at 0x7f47df4372f0>

    def _commit_gen(self) -> PQGen[None]:
        """Generator implementing `Connection.commit()`."""
        if self._num_transactions:
            raise e.ProgrammingError(
                "Explicit commit() forbidden within a Transaction "
                "context. (Transaction will be automatically committed "
                "on successful exit from context.)"
            )
        if self._tpc:
            raise e.ProgrammingError(
                "commit() cannot be used during a two-phase transaction"
            )
        if self.pgconn.transaction_status == IDLE:
            return
    
>       yield from self._exec_command(b"COMMIT")

.venv/lib/python3.13............/site-packages/psycopg/_connection_base.py:580: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <psycopg.Connection [BAD] at 0x7f47df4372f0>, command = b'COMMIT'
result_format = <Format.TEXT: 0>

    def _exec_command(
        self, command: Query, result_format: pq.Format = TEXT
    ) -> PQGen[PGresult | None]:
        """
        Generator to send a command and receive the result to the backend.
    
        Only used to implement internal commands such as "commit", with eventual
        arguments bound client-side. The cursor can do more complex stuff.
        """
        self._check_connection_ok()
    
        if isinstance(command, str):
            command = command.encode(self.pgconn._encoding)
        elif isinstance(command, Composable):
            command = command.as_bytes(self)
    
        if self._pipeline:
            cmd = partial(
                self.pgconn.send_query_params,
                command,
                None,
                result_format=result_format,
            )
            self._pipeline.command_queue.append(cmd)
            self._pipeline.result_queue.append(None)
            return None
    
        # Unless needed, use the simple query protocol, e.g. to interact with
        # pgbouncer. In pipeline mode we always use the advanced query protocol
        # instead, see #350
        if result_format == TEXT:
            self.pgconn.send_query(command)
        else:
            self.pgconn.send_query_params(command, None, result_format=result_format)
    
        result: PGresult = (yield from generators.execute(self.pgconn))[-1]
        if result.status != COMMAND_OK and result.status != TUPLES_OK:
            if result.status == FATAL_ERROR:
>               raise e.error_from_result(result, encoding=self.pgconn._encoding)
E               django.db.utils.IntegrityError: insert or update on table "authentik_core_token" violates foreign key constraint "authentik_core_token_user_id_479d5b79_fk_authentik_core_user_id"
E               DETAIL:  Key (user_id)=(2) is not present in table "authentik_core_user".

.venv/lib/python3.13............/site-packages/psycopg/_connection_base.py:478: IntegrityError

To view more test analytics, go to the Test Analytics Dashboard
📋 Got 3 mins? Take this short survey to help us improve Test Analytics.

@BeryJu BeryJu merged commit 6682136 into version-2025.10 Oct 30, 2025
115 of 128 checks passed
@BeryJu BeryJu deleted the cherry-pick/17783-to-version-2025.10 branch October 30, 2025 23:33
@github-project-automation github-project-automation bot moved this from Todo to Done in authentik Core Oct 30, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

2 participants