odysseus-dev/odysseus · error · Error

Unknown device-flow provider: ${provider}

Error message

Unknown device-flow provider: ${provider}

What it means

Thrown at the top of runProviderDeviceFlow when the provider string is not a key in PROVIDER_DEVICE_FLOWS. It fails before any network activity — pure config/validation failure. The provider comes from whatever caller passed (typically a button's data attribute or settings).

Source

Thrown at static/js/providerDeviceFlow.js:75

  const response = await fetchImpl(url, options);
  const payload = await _jsonOrEmpty(response);
  if (!response.ok) {
    throw new Error(_messageFromPayload(payload, fallback || `Request failed (HTTP ${response.status})`));
  }
  return payload;
}

function _defaultSleep(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

async function _callCallback(fn, payload) {
  if (typeof fn === 'function') await fn(payload);
}

export async function runProviderDeviceFlow(provider, options = {}) {
  const cfg = PROVIDER_DEVICE_FLOWS[provider];
  if (!cfg) throw new Error(`Unknown device-flow provider: ${provider}`);

  const fetchImpl = options.fetchImpl || globalThis.fetch?.bind(globalThis);
  if (!fetchImpl) throw new Error('Fetch API is unavailable');

  const openWindow = options.openWindow || ((url) => {
    if (globalThis.window && typeof globalThis.window.open === 'function') {
      globalThis.window.open(url, '_blank', 'noopener');
    }
  });
  const sleep = options.sleep || _defaultSleep;
  const now = options.now || (() => Date.now());
  const formData = options.formData || _formData();

  const start = await _fetchJson(fetchImpl, cfg.startUrl, {
    method: 'POST',
    body: formData,
    credentials: 'same-origin',
  }, `Failed to start ${cfg.label} sign-in`);

View on GitHub (pinned to f9235ebbf1)

Solutions

  1. Log/console the provider string being passed and compare with the keys exported in PROVIDER_DEVICE_FLOWS.
  2. Use the exact slug from the registry (case-sensitive).
  3. If UI references a provider the registry lacks, update the bundle or add the provider config.
  4. Guard with Object.hasKey check before invoking (see typeGuard).
Defensive patterns

Strategy: type-guard

Validate before calling

import { PROVIDER_DEVICE_FLOWS } from './providerDeviceFlow.js';
if (!Object.prototype.hasOwnProperty.call(PROVIDER_DEVICE_FLOWS, provider)) { showError(`Unsupported provider: ${provider}`); return; }

Type guard

const isKnownProvider = (p) => typeof p === 'string' && Object.prototype.hasOwnProperty.call(PROVIDER_DEVICE_FLOWS, p);

Try / catch

try { await runProviderDeviceFlow(provider); } catch (e) { if (/Unknown device-flow provider/.test(e.message)) showError('This sign-in provider is not available in this build'); else throw e; }

Prevention

When it happens

Trigger: Calling runProviderDeviceFlow('github') when the registry only has entries like 'google'/'anthropic'; a typo or case mismatch ('Google'); a provider removed in a newer build while old UI markup still references it.

Common situations: Frontend/backend version skew after adding a new provider to the UI but not to the flow registry; stale cached JS bundle referencing an old provider id; hand-written integrations copying the wrong provider slug.

Related errors


AI-assisted analysis of odysseus-dev/odysseus@f9235ebbf1 (2026-08-14). Data as JSON: /api/errors/ddd20691cc277ea8. Report an issue: GitHub.