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

Could not validate the SCIM settings.

Error message

Could not validate the SCIM settings.

What it means

saveSettings() runs the request payload through ScimSettingsForm::execute() (using 'update' or 'extended' validation mode). If any field fails the form rules (setting_id format, secret_token shape, etc.), a FormValidationException with this generic message is thrown; the per-field errors are attached to the exception's form object.

Solutions

  1. Read the form errors from the 400 response body (CakePHP forms serialize errors per field) and fix the reported field(s).
  2. Ensure setting_id and scim_user_id are valid UUIDs and secret_token starts with 'pb_' followed by the expected base64url body (46 chars total, see SCIM_SECRET_TOKEN_PREFIX).
  3. If updating, include the dummy token sentinel ('pb_0000...0') when the token should be kept unchanged instead of omitting or blanking secret_token.
  4. Diff your payload against the ScimSettingsForm validation rules in plugins/PassboltEe/Scim/src/Form/Settings/ScimSettingsForm.php.

Example fix

// before
{ "secret_token": "my-secret" }
// after
{ "setting_id": "5b06e2b6-...
Defensive patterns

Strategy: validation

Validate before calling

function validateScimPayload(p) {
  const uuid = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
  if (!uuid.test(p.setting_id)) return 'setting_id must be a UUID';
  if (!/^pb_[A-Za-z0-9_-]{43}$/.test(p.secret_token)) return 'secret_token must be pb_ + 43 chars';
  return null;
}

Try / catch

try {
  await saveSettings(payload);
} catch (e) {
  if (e.response?.status === 400 && e.response.data?.errors) {
    console.error('Field errors:', e.response.data.errors); // fix per-field
  }
}

Prevention

When it happens

Trigger: POST/PUT /scim-settings with a payload missing required fields (e.g. setting_id), an invalid secret_token format (must match the pb_ prefixed token pattern), or invalid setting_id/scim_user_id values.

Common situations: Provisioning scripts posting incomplete payloads, clients sending the bcrypt hash instead of a plaintext pb_ token, typos in field names, or integrations built against an older API schema before a required field was added.

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

Appendix: source

Thrown at plugins/PassboltEe/Scim/src/Service/ScimSetSettingsService.php:71

     * @throws \Exception
     */
    public function saveSettings(UserAccessControl $uac, array $data, ?string $id = null): array
    {
        // Capture the raw plaintext token before form hashes it with bcrypt
        $rawSecretToken = $data['secret_token'] ?? null;

        $form = new ScimSettingsForm();
        if ($id) {
            if (!Validation::uuid($id)) {
                throw new BadRequestException(__('The SCIM setting identifier should be a valid UUID.'));
            }
            $data['id'] = $id;
        }

        // Using this approach to avoid checking for setting_id duplicates on update
        $validate = $id ? 'update' : 'extended';
        if (!$form->execute($data, ['validate' => $validate])) {
            throw new FormValidationException(
                __('Could not validate the SCIM settings.'),
                $form
            );
        }

        /** @var \Passbolt\Scim\Model\Table\ScimSettingsTable $scimSettingsTable */
        $scimSettingsTable = $this->fetchTable('Passbolt/Scim.ScimSettings');
        /** @var \Passbolt\Scim\Model\Entity\ScimSetting|null $current */
        $current = $scimSettingsTable->find()->first();
        if (!$current && $id) {
            throw new NotFoundException(__('The SCIM plugin is disabled.'));
        }
        if (!$id && $current) {
            throw new BadRequestException(__('Please delete previous settings before creating again.'));
        }
        if ($current && $current->id !== $id) {
            throw new NotFoundException(__('The uuid in the url doesn\'t match any known setting record.'));
        }

View on GitHub (pinned to 31c1bbc10f)