different-ai/openwork · error

Failed to reconcile SCIM (${response.status}).

Error message

Failed to reconcile SCIM (${response.status}).

What it means

handleRunReconciliation in scim-screen.tsx throws this when POST /v1/scim/reconcile returns non-ok. Reconciliation pushes org group/user mappings to the identity provider and can be slow; the error means the server rejected or failed the run. After success the code reloads the SCIM config; after this throw the reconcile flag is reset in finally.

Source

Thrown at ee/apps/den-web/app/(den)/dashboard/_components/scim-screen.tsx:223

    if (!orgId) {
      setError("Organization not found.");
      return;
    }

    setError(null);
    try {
      await runReauthableAction("reconcile-scim", async () => {
        setReconciling(true);
        try {
          const { response, payload } = await requestJson(
            "/v1/scim/reconcile",
            { method: "POST", body: JSON.stringify({}) },
            12000,
          );

          if (!response.ok) {
            throw getRequestError(payload, response, `Failed to reconcile SCIM (${response.status}).`);
          }

          await loadScimConfig();
        } finally {
          setReconciling(false);
        }
      });
    } catch (nextError) {
      setError(
        nextError instanceof Error ? nextError.message : "Failed to reconcile SCIM.",
      );
    }
  }

  async function handleGroupMappingChange() {
    if (!access.canManageScim) {
      setError("Only workspace owners and super-admins can change SCIM mappings.");
      return;

View on GitHub (pinned to 2b7df46e8a)

Solutions

  1. For timeouts on large directories, retry — or run reconciliation server-side/off-peak and poll status.
  2. Check status 401/403: re-authenticate or use an admin account.
  3. 404: provision the SCIM connection before reconciling.
  4. Disable the reconcile button while a run is pending to avoid 409s.

Example fix

// before: button stays clickable during a run
<button onClick={handleRunReconciliation}>Reconcile</button>
// after: disable while running
<button disabled={reconciling} onClick={handleRunReconciliation}>Reconcile</button>
Defensive patterns

Strategy: retry

Validate before calling

if (reconciling) return; // already in progress
if (!connection) throw new Error('Provision the SCIM connection before reconciling.');

Type guard

function canReconcile(v: unknown): v is { connection: unknown; reconciling: false } {
  return typeof v === 'object' && v !== null &&
    (v as Record<string, unknown>).connection != null &&
    (v as Record<string, unknown>).reconciling === false;
}

Try / catch

try {
  await runReconciliation();
  toast('Reconciliation started.');
} catch (e) {
  const msg = e instanceof Error ? e.message : String(e);
  if (/timed out|\(5\d\d\)/i.test(msg)) toast('Reconciliation is still running server-side; check status shortly.');
  else if (msg.includes('409')) toast('A reconciliation is already in progress.');
  else toast(msg);
}

Prevention

When it happens

Trigger: POST /v1/scim/reconcile with empty body returns 401/403 (auth/permission), 404 (no SCIM connection), 409 (a reconcile run is already in progress), 422 (identity provider rejects the sync), or 5xx/timeout (reconcile exceeding the 12s window on large directories).

Common situations: Large orgs where reconciliation takes longer than the client timeout; IdP credentials revoked or token rotated but not yet synced; double-clicking the reconcile button triggering concurrent runs.

Related errors


AI-assisted analysis of different-ai/openwork@2b7df46e8a (2026-09-01). Data as JSON: /api/errors/07f86617faae8182. Report an issue: GitHub.