tinyhumansai/openhuman · warning · Error

OpenHuman uses the session JWT — keys are not configurable…

Error message

OpenHuman uses the session JWT — keys are not configurable here.

What it means

setCloudProviderKey(slug, apiKey) stores a per-provider API key via authStoreProviderCredentials using the 'provider:<slug>' key format. The 'openhuman' slug is explicitly rejected because OpenHuman's own inference/auth uses the session JWT — there is no user-configurable API key for it, so attempting to store one throws this explanatory error before any storage call.

Solutions

  1. Filter the 'openhuman' slug out before calling — never send it to setCloudProviderKey.
  2. In the settings UI, hide the API-key input for the openhuman provider and show 'uses your OpenHuman login' instead.
  3. For tests, mock the function or skip the slug rather than expecting storage to no-op.
  4. If OpenHuman auth is failing, the fix is signing in (session JWT), not setting a key.

Example fix

// before
for (const [slug, key] of Object.entries(keys)) {
  await setCloudProviderKey(slug, key);
}

// after
for (const [slug, key] of Object.entries(keys)) {
  if (slug === 'openhuman') continue; // uses session JWT, no key
  await setCloudProviderKey(slug, key);
}
Defensive patterns

Strategy: validation

Validate before calling

const USER_KEY_PROVIDERS = new Set(['openhuman']);

function isKeyConfigurable(slug: string): boolean {
  return !USER_KEY_PROVIDERS.has(slug);
}
if (isKeyConfigurable(slug)) {
  await setCloudProviderKey(slug, apiKey);
}

Type guard

function isConfigurableProviderSlug(slug: string): boolean {
  return slug !== 'openhuman';
}

Try / catch

try {
  await setCloudProviderKey(slug, apiKey);
} catch (err) {
  if (err instanceof Error && err.message.includes('keys are not configurable')) {
    return; // expected for the openhuman slug — no-op, not an error state
  }
  throw err;
}

Prevention

When it happens

Trigger: Calling setCloudProviderKey('openhuman', ...) — typically from a settings screen that renders the same form for every provider slug, or from import/sync code that bulk-writes all provider keys including the OpenHuman entry.

Common situations: Generic provider-key UI not special-casing the built-in provider; migration scripts copying keys across profiles without filtering; QA/test harness iterating all slugs.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


AI-assisted analysis of tinyhumansai/openhuman@7491200858 (2026-08-17). Data as JSON: /api/errors/edc40f4d180127b6. Report an issue: GitHub.

Appendix: source

Thrown at app/src/services/api/aiSettingsApi.ts:453

      !!m &&
      m.vision === e.vision &&
      m.cost_per_1m_output === e.cost_per_1m_output &&
      (m.cost_per_1m_input ?? 0) === (e.cost_per_1m_input ?? 0) &&
      (m.cost_per_1m_cached_input ?? 0) === (e.cost_per_1m_cached_input ?? 0) &&
      (m.context_window ?? 0) === (e.context_window ?? 0)
    );
  });
}

// ─── API key management (per cloud provider slug) ──────────────────────────

/**
 * Store an API key for a cloud provider (encrypted at rest). Keyed by slug
 * using the new `provider:<slug>` format.
 */
export async function setCloudProviderKey(slug: string, apiKey: string): Promise<void> {
  if (slug === 'openhuman') {
    throw new Error('OpenHuman uses the session JWT — keys are not configurable here.');
  }
  // Store under both new-style key `provider:<slug>` and legacy bare `<slug>`
  // so old code paths that look up by bare slug continue to work.
  await authStoreProviderCredentials({
    provider: authKeyForSlug(slug),
    profile: 'default',
    token: apiKey,
    setActive: true,
  });
}

/**
 * Outcome of a post-save connection check (#5146 §2.4).
 *
 * `ok: false` means the credential was stored but the provider could not
 * actually serve an inference call — the "connected but unusable" state where
 * the UI previously showed a healthy provider that failed on first real use.
 */

View on GitHub (pinned to 7491200858)