passbolt/passbolt_api · error · Cake\Http\Exception\NotFoundException

The SCIM plugin is disabled.

Error message

The SCIM plugin is disabled.

What it means

After form validation, saveSettings() loads the single current scim_settings row. If no row exists (plugin effectively not configured) but the client supplied an $id to update, it throws NotFoundException with the (somewhat confusing) message 'The SCIM plugin is disabled.' — the record being updated does not exist.

Solutions

  1. Call GET /scim-settings first; if it returns no settings, create them with POST instead of PUT.
  2. Refresh the client's cached settings id after any deletion — the old UUID is permanently invalid.
  3. Enable/configure the SCIM plugin if it was expected to be configured on this instance.
Defensive patterns

Strategy: validation

Validate before calling

const settings = await (await fetch('/scim-settings.json')).json();
if (!settings.data) {
  // no settings row exists: use POST create, never PUT
}

Try / catch

try {
  await api.put(`/scim-settings/${id}.json`, payload);
} catch (e) {
  if (e.response?.status === 404) {
    const { data } = await api.get('/scim-settings.json');
    if (!data) await api.post('/scim-settings.json', payload); // create instead
  }
}

Prevention

When it happens

Trigger: PUT /scim-settings/<uuid> (or DELETE-style update flows) when the scim_settings table is empty — i.e., SCIM settings were never created or were already deleted.

Common situations: Client caching a settings id from a previous installation or after another admin deleted the settings; racing two admins where one deletes while the other updates; scripts replaying recorded PUT requests against a fresh instance.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


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

Appendix: source

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

            }
            $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.'));
        }

        $currentValue = [];
        $isDummyToken = $rawSecretToken === self::SCIM_SECRET_TOKEN_DUMMY;
        if ($current) {
            $currentValue = $this->decryptSettings($current);
            $form->set('setting_id', Hash::get($currentValue, 'setting_id'));
            if (!$form->getData('secret_token') || $isDummyToken) {
                $form->set('secret_token', Hash::get($currentValue, 'secret_token'));
            }
        }

View on GitHub (pinned to 31c1bbc10f)