{"record":{"id":"896a3dfcab60c5d1","repo":"passbolt/passbolt_api","slug":"invalid-mfa-org-settings","errorCode":null,"errorMessage":"Invalid MFA org settings.","messagePattern":"Invalid MFA org settings\\.","errorType":"http","errorClass":"InternalErrorException","httpStatus":500,"severity":"error","filePath":"plugins/PassboltCe/MultiFactorAuthentication/src/Utility/MfaOrgSettings.php","lineNumber":65,"sourceCode":"    /**\n     * @var \\App\\Model\\Table\\OrganizationSettingsTable\n     */\n    protected OrganizationSettingsTable $OrganizationSettings;\n\n    /**\n     * @var array|null\n     */\n    protected ?array $settings = null;\n\n    /**\n     * MfaOrgSettings constructor.\n     *\n     * @param array|null $settings merged settings from configure and database\n     */\n    public function __construct(?array $settings = null)\n    {\n        if (!isset($settings) || !isset($settings[MfaSettings::PROVIDERS])) {\n            throw new InternalErrorException('Invalid MFA org settings.');\n        }\n        $settings[MfaSettings::PROVIDERS] = $this->formatProviders($settings[MfaSettings::PROVIDERS]);\n        $this->settings = $settings;\n        $this->OrganizationSettings = TableRegistry::getTableLocator()->get('OrganizationSettings');\n    }\n\n    /**\n     * Format Providers\n     *\n     * We accept both format ['providers' => ['totp' => true ]] and ['providers' => ['totp']]\n     * This function format the former to the latter to ensure consistent format\n     *\n     * @param array $providers see above\n     * @return array\n     */\n    private function formatProviders(array $providers): array\n    {\n        $result = $providers;","sourceCodeStart":47,"sourceCodeEnd":83,"githubUrl":"https://github.com/passbolt/passbolt_api/blob/31c1bbc10f32808a607fa9bd81891e898779c0bc/plugins/PassboltCe/MultiFactorAuthentication/src/Utility/MfaOrgSettings.php#L47-L83","documentation":"MfaOrgSettings::__construct() requires a merged settings array (from config + database) containing the 'providers' key. It throws InternalErrorException when $settings is null or lacks PROVIDERS — the org-level MFA settings are missing or malformed, which the class treats as a server-side invariant violation rather than a user error.","triggerScenarios":"Constructing MfaOrgSettings with null (no org settings stored in OrganizationSettings table) or an array without the 'providers' key; calling MfaOrgSettings::get() when no MFA org settings were ever saved.","commonSituations":"Fresh passbolt instance where admins never configured MFA org settings; code paths reading org settings before the MFA settings page was saved; database row missing after migration; manually deleted OrganizationSettings record; passing unmerged config arrays in tests.","solutions":["Initialize the constructor input with a default containing providers: pass ['providers' => [...defaults]] when the stored settings are null.","Call MfaOrgSettings::getOrCreate() or equivalent factory that falls back to defaults instead of raw new MfaOrgSettings(null).","Save valid MFA org settings via the admin MFA settings endpoint so the database record exists.","Catch InternalErrorException in higher-level service code and fall back to default provider lists."],"exampleFix":"// before\n$orgSettings = new MfaOrgSettings($dbSettings); // $dbSettings may be null\n// after\n$orgSettings = new MfaOrgSettings($dbSettings ?? ['providers' => MfaSettings::PROVIDERS_ALLOWED]);","handlingStrategy":"validation","validationCode":"$settings = $settings ?? [];\nif (!isset($settings[MfaSettings::PROVIDERS])) {\n    $settings[MfaSettings::PROVIDERS] = MfaSettings::PROVIDERS_ALLOWED;\n}\n$orgSettings = new MfaOrgSettings($settings);","typeGuard":"$isValid = is_array($settings) && array_key_exists(MfaSettings::PROVIDERS, $settings);","tryCatchPattern":"try { $s = new MfaOrgSettings($raw); } catch (\\Cake\\Http\\Exception\\InternalErrorException $e) { $s = new MfaOrgSettings(['providers' => []]); }","preventionTips":["Use factory methods (getOrCreate) that supply defaults instead of raw construction","Never pass raw null DB rows into the constructor — merge with default providers","Ensure OrganizationSettings record for MFA exists before building org settings"],"tags":["mfa","org-settings","internal-error","constructor"],"backgroundTag":"missing-required-config-field","analyzedSha":"31c1bbc10f32808a607fa9bd81891e898779c0bc","analyzedAt":"2026-09-17T00:04:38.960Z","contentChangedAt":"2026-09-17T00:04:38.960Z","schemaVersion":2},"datasetVersion":"2026-09-21T09:17:21.228Z"}