passbolt/passbolt_api · error · CustomValidationException

Could not validate Duo configuration

Error message

Could not validate Duo configuration

What it means

Thrown by MfaOrgSettingsDuoService::validateDuoSettings() when any Duo setting fails validation (missing/empty fields or failed Duo health check). It raises a CustomValidationException carrying per-field errors under the 'duo' provider key.

Solutions

  1. Read $errors in the CustomValidationException response for the exact failing field.
  2. Ensure client id (integration key), client secret, and api hostname are all non-empty and correctly formatted.
  3. Verify credentials against the Duo Admin Panel application protecting passbolt.
  4. Confirm the server can reach Duo's API for the health check (network/firewall).
  5. Trim whitespace/quotes from pasted secrets.

Example fix

// before: incomplete payload
{"duo": {"clientId": "DI..."}}
// after: complete settings
{"duo": {"clientId": "DI...", "clientSecret": "...", "apiHostname": "sso-abc.sso.duosecurity.com"}}
Defensive patterns

Strategy: validation

Validate before calling

$duo = $payload['duo'] ?? [];
$required = ['clientId', 'clientSecret', 'apiHostname'];
foreach ($required as $field) {
    if (empty(trim($duo[$field] ?? ''))) {
        throw new CustomValidationException("Missing duo field: $field");
    }
}

Try / catch

try {
    $service->validateDuoSettings($data);
} catch (CustomValidationException $e) {
    return $this->response->withStatus(400)->withErrors($e->getErrors());
}

Prevention

When it happens

Trigger: POST/PUT /mfa/policies/duo.json with missing client id, client secret, api hostname, empty values, or when the Duo health check API call fails.

Common situations: Typo in the Duo integration key/secret; pasting values with whitespace or quotes; wrong api hostname format (missing sso-*.sso.duosecurity.com pattern); Duo application deleted or disabled on the Duo side.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


AI-assisted analysis of passbolt/passbolt_api@31c1bbc10f (2026-09-17). Data as JSON: /api/errors/5b05cac6f2756463. Report an issue: GitHub.

Appendix: source

Thrown at plugins/PassboltCe/MultiFactorAuthentication/src/Service/MfaOrgSettings/MfaOrgSettingsDuoService.php:141

            $errors[MfaSettings::PROVIDER_DUO][MfaOrgSettings::DUO_CLIENT_ID]['notEmpty'] = $msg;
        }

        if ($performHealthcheck && empty($errors[MfaSettings::PROVIDER_DUO])) {
            try {
                $duoClient = $client ?? (new MfaDuoGetSdkClientService())->getOrFail(
                    $this,
                    AuthenticationToken::TYPE_MFA_SETUP
                );
                $duoClient->healthCheck();
            } catch (DuoException | InternalErrorException $e) {
                $msg = __('Cannot verify Duo settings.') . ' ' . $e->getMessage();
                $errors[MfaSettings::PROVIDER_DUO][MfaOrgSettings::DUO_HEALTH_CHECK] = $msg;
            }
        }

        if (count($errors) !== 0) {
            $msg = __('Could not validate Duo configuration');
            throw new CustomValidationException($msg, $errors);
        }
    }

    /**
     * Get Duo provider setting.
     *
     * @param string $settingKey organization settings key
     * @param string $errorMessage error message if organization settings key is not found
     * @return string
     * @throws \Cake\Datasource\Exception\RecordNotFoundException if setting is missing
     */
    private function getSetting(string $settingKey, string $errorMessage): string
    {
        if (!isset($this->settings[MfaSettings::PROVIDER_DUO][$settingKey])) {
            throw new RecordNotFoundException($errorMessage);
        }

        return $this->settings[MfaSettings::PROVIDER_DUO][$settingKey];

View on GitHub (pinned to 31c1bbc10f)