passbolt/passbolt_api · error · Passbolt\Scim\Exception\FormValidationException

Could not validate the SCIM settings found in database.

Error message

Could not validate the SCIM settings found in database.

What it means

ScimGetSettingsService::getSettings() reads the single SCIM settings row from the database, decrypts it, and re-validates it with ScimSettingsForm. If the stored data fails form validation, it wraps the failure in an InternalErrorException with this message. This signals corrupted, legacy-format, or manually-tampered SCIM settings persisted in the `scim_settings` table — not a client input problem.

Solutions

  1. Inspect the decrypted settings row: delete the row from scim_settings so the plugin falls back to default (unset) settings, then re-create the SCIM settings via the admin UI.
  2. Check the form errors (they are attached to the chained FormValidationException) via the exception stack/log to see exactly which field failed validation.
  3. Verify the server encryption keys are intact — a wrong key yields garbage on decryptSettings(), which then fails validation.
  4. If this appeared after a passbolt upgrade, compare ScimSettingsForm validation rules with the stored data and migrate the row to the expected format instead of deleting.

Example fix

// Remove corrupted row so defaults are used (MySQL)
DELETE FROM scim_settings WHERE id = '<corrupted-row-uuid>';
// Then re-save SCIM settings through Admin > SCIM settings UI
Defensive patterns

Strategy: try-catch

Try / catch

try {
    $settings = (new ScimGetSettingsService())->getSettings();
} catch (InternalErrorException $e) {
    $previous = $e->getPrevious();
    if ($previous instanceof FormValidationException) {
        Log::error('SCIM settings corrupt: ' . json_encode($previous->getForm()->getErrors()));
    }
    // fall back to default/unset settings and prompt admin to re-save
}

Prevention

When it happens

Trigger: GET /scim-settings (admin settings read) when a row exists in scim_settings whose decrypted payload fails ScimSettingsForm validation: e.g. missing required keys, malformed setting_id/scim_user_id, or values written by an older plugin version whose schema no longer validates.

Common situations: Manual edits to the scim_settings table rows, restore of a database from an older passbolt version, partial/corrupted encrypted payload after key changes, or an upgrade that tightened ScimSettingsForm validation rules against previously-accepted data.

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/6cb7013c80893e44. Report an issue: GitHub.

Appendix: source

Thrown at plugins/PassboltEe/Scim/src/Service/ScimGetSettingsService.php:74

        /** @var \Passbolt\Scim\Model\Table\ScimSettingsTable $scimSettingsTable */
        $scimSettingsTable = $this->fetchTable('Passbolt/Scim.ScimSettings');

        /** @var \Passbolt\Scim\Model\Entity\ScimSetting|null $settings */
        $settings = $scimSettingsTable->find()->first();

        if (is_null($settings)) {
            return null;
        }
        $value = $this->decryptSettings($settings);
        $form = new ScimSettingsForm();

        if (!$form->execute($value, ['newRecord' => false])) {
            $validationException = new FormValidationException(
                __('Could not validate the SCIM settings found in database.'),
                $form
            );

            throw new InternalErrorException($validationException->getMessage(), 500, $validationException);
        }

        return ScimSettingsDto::createFromArray([
            'id' => $settings->id,
            'setting_id' => Hash::get($value, 'setting_id'),
            'scim_user_id' => Hash::get($value, 'scim_user_id'),
            'base_api_endpoint' => Router::url('scim/v2/' . Hash::get($value, 'setting_id'), true),
            'expired' => Hash::get($value, 'expired'),
            'created' => $settings->created,
            'created_by' => $settings->created_by,
            'modified' => $settings->modified,
            'modified_by' => $settings->modified_by,
        ]);
    }
}

View on GitHub (pinned to 31c1bbc10f)