{"record":{"id":"b57c003b4ee4e313","repo":"passbolt/passbolt_api","slug":"could-not-validate-multi-factor-authentication-provider","errorCode":null,"errorMessage":"Could not validate multi-factor authentication provider configuration.","messagePattern":"Could not validate multi-factor authentication provider configuration\\.","errorType":"validation","errorClass":"CustomValidationException","httpStatus":400,"severity":"error","filePath":"plugins/PassboltCe/MultiFactorAuthentication/src/Utility/MfaOrgSettings.php","lineNumber":316,"sourceCode":"                        (new MfaOrgSettingsDuoService($data))->validateDuoSettings($client, $skipHealthcheck === false);\n                    } catch (CustomValidationException $exception) {\n                        $errors = $exception->getErrors();\n                    }\n                    break;\n                case MfaSettings::PROVIDER_TOTP:\n                    // Nothing else to validate\n                    break;\n                default:\n                    $errors[$provider]['invalidProvider'] = __('Unknown MFA provider: {0}.', $provider);\n                    break;\n            }\n            if (isset($errors[$provider])) {\n                $results[$provider] = $errors[$provider];\n            }\n        }\n        if (count($results) !== 0) {\n            $msg = __('Could not validate multi-factor authentication provider configuration.');\n            throw new CustomValidationException($msg, $results);\n        }\n\n        return true;\n    }\n\n    /**\n     * Save a user provided org settings in database\n     *\n     * @throws \\App\\Error\\Exception\\CustomValidationException in case of validation error\n     * @throws \\Cake\\Http\\Exception\\InternalErrorException\n     * @param array $data user provided input\n     * @param \\App\\Utility\\UserAccessControl $uac user access control\n     * @param \\Duo\\DuoUniversal\\Client|null $client Duo SDK Client\n     * @param array $options Options used to save & validate organisation settings\n     * @return void\n     */\n    public function save(array $data, UserAccessControl $uac, ?Client $client = null, array $options = []): void\n    {","sourceCodeStart":298,"sourceCodeEnd":334,"githubUrl":"https://github.com/passbolt/passbolt_api/blob/31c1bbc10f32808a607fa9bd81891e898779c0bc/plugins/PassboltCe/MultiFactorAuthentication/src/Utility/MfaOrgSettings.php#L298-L334","documentation":"After validating each individual provider's configuration, MfaOrgSettings::validate() aggregates per-provider errors and throws CustomValidationException (with the error details as its second argument) if any provider failed. It signals that at least one provider's org-level configuration is invalid.","triggerScenarios":"Calling validate()/save() where a per-provider form (e.g. MfaOrgSettingsTotpForm or yubikey form) fails validation — e.g. invalid TOTP issuer, missing/invalid yubikey clientId or secretKey format — populating $results with errors.","commonSituations":"Admin saving org MFA settings with a typo in provider config values; yubikey clientId/secretKey failing validation after a change at YubiCo; invalid issuer/OTP digits in TOTP org settings; API clients posting raw config that never passed client-side validation.","solutions":["Inspect the exception's validation errors (its second argument) to identify which provider and field failed, fix those values, and resubmit.","Run the provider form validation client-side or in the service before calling save().","Verify each provider's config against the provider form rules: issuer format for totp, numeric clientId and non-empty secretKey for yubikey.","Catch CustomValidationException and surface $e->getErrors() to the admin UI.","exampleFixPlaceholder"],"exampleFix":"// before\ntry {\n    $orgSettings->save($data);\n} catch (\\App\\Error\\Exception\\CustomValidationException $e) {\n    throw new InternalErrorException($e->getMessage());\n}\n// after\ntry {\n    $orgSettings->save($data);\n} catch (\\App\\Error\\Exception\\CustomValidationException $e) {\n    throw new BadRequestException($e->getMessage(), 400, $e); // include $e->getErrors() in response\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try { $orgSettings->save($data); } catch (\\App\\Error\\Exception\\CustomValidationException $e) { $errors = $e->getErrors(); /* surface per-provider errors to client */ }","preventionTips":["Always inspect the exception's error details, not just the message","Run each provider's form validation before assembling the save payload","Keep org provider config values aligned with the provider form rules (issuer, clientId, secretKey formats)"],"tags":["mfa","validation","provider-config"],"backgroundTag":"schema-validation-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"}