{"record":{"id":"c269933b8845fe9b","repo":"passbolt/passbolt_api","slug":"the-sso-state-could-not-be-saved","errorCode":null,"errorMessage":"The SSO state could not be saved.","messagePattern":"The SSO state could not be saved\\.","errorType":"http","errorClass":"InternalErrorException","httpStatus":500,"severity":"critical","filePath":"plugins/PassboltEe/Sso/src/Service/SsoStates/SsoStatesAssertService.php","lineNumber":169,"sourceCode":"        }\n    }\n\n    /**\n     * Marks given state as deleted.\n     *\n     * @param \\Passbolt\\Sso\\Model\\Entity\\SsoState $ssoState SSO state entity.\n     * @return void\n     * @throws \\Cake\\Http\\Exception\\InternalErrorException When unable to save the SSO state entity.\n     */\n    private function consume(SsoState $ssoState): void\n    {\n        /** @var \\Passbolt\\Sso\\Model\\Table\\SsoStatesTable $ssoStatesTable */\n        $ssoStatesTable = $this->fetchTable('Passbolt/Sso.SsoStates');\n\n        $ssoState->deleted = DateTime::now();\n\n        if (!$ssoStatesTable->save($ssoState)) {\n            throw new InternalErrorException(__('The SSO state could not be saved.'));\n        }\n    }\n}\n","sourceCodeStart":151,"sourceCodeEnd":173,"githubUrl":"https://github.com/passbolt/passbolt_api/blob/31c1bbc10f32808a607fa9bd81891e898779c0bc/plugins/PassboltEe/Sso/src/Service/SsoStates/SsoStatesAssertService.php#L151-L173","documentation":"After assertions, consume() marks the SSO state as used by setting deleted = now() and saving it. If the save fails, an InternalErrorException (HTTP 500) is thrown. Note the state is only 'consumed' via the deleted timestamp (soft delete); the save is essential to make single-use states unusable, so a failure here is treated as a server fault.","triggerScenarios":"SsoStatesTable->save($ssoState) returns false during consume(), called at the end of assertAndConsume/assertAndConsumeWithoutUser (both on success and when re-throwing an assertion failure). Typical causes: entity validation errors on save, database connection failure, missing sso_states table, or the entity marked dirty-but-invalid.","commonSituations":"Database outage or connection limit reached during an SSO callback; migration not run so the sso_states table or columns (deleted) are missing; write permissions/replication issues on the DB; lock/table corruption in MySQL/Postgres.","solutions":["Check database health and application error logs for the underlying save failure (connection refused, deadlock, disk full).","Run pending migrations (passbolt migrate / ddev refresh) to ensure the sso_states schema exists and matches the code version.","Retry the SSO flow once the database is available — the state may remain unconsumed; if in doubt, re-initiate.","If it recurs on every callback, inspect SsoStatesTable validation/rules for a rule rejecting the save and check the entity's fields against the schema."],"exampleFix":"# before: schema drift after upgrade\n# after\nddev refresh   # or: bin/cake passbolt migrate\n# verify sso_states table exists with 'deleted' column","handlingStrategy":"retry","validationCode":"// Pre-check DB availability before SSO callback processing\ntry {\n    $conn = ConnectionManager::get('default');\n    $conn->execute('SELECT 1 FROM sso_states LIMIT 1');\n} catch (Throwable $e) {\n    // DB unreachable: fail fast instead of a 500 mid-consume\n}","typeGuard":"function isSavable(SsoState $ssoState): bool {\n    return $ssoState->id !== null && $ssoState->deleted === null;\n}","tryCatchPattern":"try {\n    $service->assertAndConsume($ssoState, $settingsId, $uac);\n} catch (InternalErrorException $e) {\n    if ($e->getMessage() === 'The SSO state could not be saved.') {\n        // check DB health / run migrations, then retry the flow\n    }\n    throw $e;\n}","preventionTips":["Run bin/cake passbolt migrate after every upgrade.","Monitor DB connectivity and disk space.","Check error logs for the real save failure (validation rule, deadlock, connection).","Verify sso_states schema has the deleted column."],"tags":["sso","database","internal-error","http-500","oauth-state"],"backgroundTag":"database-write-failed","analyzedSha":"31c1bbc10f32808a607fa9bd81891e898779c0bc","analyzedAt":"2026-09-17T00:04:38.960Z","contentChangedAt":"2026-09-17T00:04:38.960Z","schemaVersion":2},"datasetVersion":"2026-09-21T04:17:39.646Z"}