Mintplex-Labs/anything-llm · error

${result.error}

Error message

${result.error}

What it means

The 400 reply from POST /admin/agent-skills/outlook/auth-url when outlookLib.getAuthUrl(redirectUri) reports failure. getAuthUrl re-reads the saved Outlook config and fails when clientId is empty (config incomplete) or validateOrganizationAuth() rejects it (organization authType without tenantId). Because the endpoint just wrote clientId into the config, seeing this usually means the saved value ended up empty (e.g. clientId was whitespace that trimmed to '') or the persisted authType/tenantId combination is inconsistent.

Source

Thrown at server/endpoints/utils/outlookAgentUtils.js:77

        // If auth type changed, clear tokens as they won't work with different authority
        if (
          existingConfig.authType &&
          existingConfig.authType !== validAuthType
        ) {
          delete configUpdate.accessToken;
          delete configUpdate.refreshToken;
          delete configUpdate.tokenExpiry;
        }

        await outlookLib.OutlookBridge.updateConfig(configUpdate);
        outlookLib.reset();

        const redirectUri = getOutlookRedirectUri(request);
        const result = await outlookLib.getAuthUrl(redirectUri);
        if (!result.success) {
          return response
            .status(400)
            .json({ success: false, error: result.error });
        }

        return response.status(200).json({ success: true, url: result.url });
      } catch (e) {
        console.error("Outlook auth URL error:", e);
        response.status(500).json({ success: false, error: e.message });
      }
    }
  );

  app.get(
    "/agent-skills/outlook/auth-callback",
    [validatedRequest, isSingleUserMode],
    async (request, response) => {
      try {
        const { code, error, error_description } = request.query;

View on GitHub (pinned to 3aec848f28)

Solutions

  1. Re-send clientId as a clean, non-empty string (no surrounding quotes) and include tenantId when using organization auth, then retry.
  2. GET the Outlook status endpoint to confirm the persisted config (clientId present, authType/tenantId consistent) before requesting the auth URL.
  3. If the stored config is scrambled, revoke (POST /admin/agent-skills/outlook/revoke) and re-configure from scratch.
Defensive patterns

Strategy: validation

Validate before calling

// Confirm persisted config is complete before requesting the auth URL
const status = await (await fetch("/api/agent-skills/outlook/status")).json();
if (!status.hasCredentials) throw new Error("Save clientId/clientSecret first");
if (status.config?.authType === "organizations" && !status.config?.tenantId) throw new Error("tenantId required for organization auth");
const { url } = await (await fetch("/api/admin/agent-skills/outlook/auth-url", { method: "POST", headers, body })).json();

Type guard

const outlookConfigComplete = (cfg) =>
  !!cfg?.clientId?.trim() &&
  (cfg.authType !== "organizations" || !!cfg.tenantId?.trim());

Prevention

When it happens

Trigger: clientId passed as whitespace/quotes trimming to an empty string; the config update persisted authType 'organization' with an empty tenantId; a stale or concurrently overwritten outlook_agent_config row between updateConfig and getConfig; redirect URI not registered in the Azure app (fails later in the browser flow rather than here).

Common situations: Quoted secret/id copied from a password manager; two admins saving conflicting Outlook configs; config row left half-written after a previous failed save; organization tenant toggled in the UI without re-entering the tenant.

Related errors


AI-assisted analysis of Mintplex-Labs/anything-llm@3aec848f28 (2026-08-18). Data as JSON: /api/errors/9eaef81b8d2412d6. Report an issue: GitHub.