{"record":{"id":"65b31d25e369305b","repo":"passbolt/passbolt_api","slug":"exception-getmessage-from-ssosettingsgetservice-draft","errorCode":null,"errorMessage":"$exception->getMessage() from SsoSettingsGetService draft failure (dynamic), remapped to 400","messagePattern":"\\$exception->getMessage\\(\\) from SsoSettingsGetService draft failure \\(dynamic\\), remapped to 400","errorType":"http","errorClass":"BadRequestException","httpStatus":400,"severity":"error","filePath":"plugins/PassboltEe/Sso/src/Controller/AbstractSso2Stage2Controller.php","lineNumber":218,"sourceCode":"        }\n\n        $this->response = $this->getResponse()->withCookie($service->clearStateCookie());\n        $this->redirect($successUrl);\n    }\n\n    /**\n     * @param \\App\\Service\\Cookie\\AbstractSecureCookieService $cookieService Cookie service\n     * @param \\Passbolt\\Sso\\Model\\Entity\\SsoState $ssoState SSO state.\n     * @param string $code jwt\n     * @return void\n     */\n    protected function stage2AsAdmin(AbstractSecureCookieService $cookieService, SsoState $ssoState, string $code): void\n    {\n        try {\n            // Get the draft settings\n            $settingsDto = (new SsoSettingsGetService())->getDraftByIdOrFail($ssoState->sso_settings_id, true);\n        } catch (Exception $exception) {\n            throw new BadRequestException($exception->getMessage(), 400, $exception);\n        }\n\n        try {\n            $service = $this->ssoServiceFactory($cookieService, $settingsDto);\n            $uac = $service->assertStateCodeAndGetUac($ssoState, $code, $this->User->ip(), $this->User->userAgent());\n        } catch (OAuth2Exception $e) { // Remap 500 error with 400 when admin is setting up SSO\n            throw new BadRequestException($e->getMessage(), 400, $e);\n        }\n\n        // Create authentication token for next step, e.g. activate settings\n        $ssoAuthToken = $service->createAuthTokenToActiveSettings($uac, $service->getSettings()->id);\n\n        $this->response = $this->getResponse()->withCookie($service->clearStateCookie());\n        $this->redirect(Router::url(\"/sso/login/dry-run/success?token={$ssoAuthToken->token}\", true));\n    }\n}\n","sourceCodeStart":200,"sourceCodeEnd":235,"githubUrl":"https://github.com/passbolt/passbolt_api/blob/31c1bbc10f32808a607fa9bd81891e898779c0bc/plugins/PassboltEe/Sso/src/Controller/AbstractSso2Stage2Controller.php#L200-L235","documentation":"In stage2AsAdmin, fetching the draft SSO settings via SsoSettingsGetService::getDraftByIdOrFail() can fail (draft missing, deleted, or wrong status). The controller catches any Exception and remaps its dynamic message to a 400 BadRequestException, chaining the original exception.","triggerScenarios":"Admin completes SSO provider callback (stage2) but the referenced sso_settings_id in the state no longer points to a valid settings draft, e.g. the draft was saved/deleted or expired between stage1 redirect and stage2 callback.","commonSituations":"Two admins editing the same SSO settings concurrently — one saves/deletes the draft while the other's callback is in flight; session left open so long the draft was discarded; clicking an old bookmarked callback link.","solutions":["Re-open the SSO settings admin screen and restart the provider setup to generate a fresh draft before completing stage2.","Check the sso_settings record in the database for the id in the state — confirm it exists with status DRAFT.","Verify no concurrent admin session deleted/modified the settings draft (check audit/logs).","Ensure the SSO state cookie and the settings draft belong to the same setup attempt; clear cookies and retry."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"const settings = await api.get('/sso/settings/' + ssoState.sso_settings_id + '.json');\nif (!settings || settings.status !== 'draft') { throw new Error('SSO settings draft missing; restart setup'); }","typeGuard":"function hasValidDraft(state) { return state != null && typeof state.sso_settings_id === 'string' && state.sso_settings_id.length > 0; }","tryCatchPattern":"try { await stage2AsAdmin(state, code); } catch (e) { if (e.status === 400) { showAlert('SSO draft settings unavailable: ' + e.message + '. Restart provider setup.'); } }","preventionTips":["Complete the SSO setup in one session without long pauses","Avoid two admins editing the same SSO settings concurrently","Check the draft still exists before finishing stage2 after long delays"],"tags":["sso","bad-request","settings-draft","admin-setup"],"backgroundTag":"resource-not-found","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"}