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
- Log/console the provider string being passed and compare with the keys exported in PROVIDER_DEVICE_FLOWS.
- Use the exact slug from the registry (case-sensitive).
- If UI references a provider the registry lacks, update the bundle or add the provider config.
- 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
- Derive provider buttons from PROVIDER_DEVICE_FLOWS keys so UI and registry cannot diverge
- Validate the provider slug before starting the flow
- Case-normalize provider strings at the call site
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
- Server has no OAuth config
- Request failed (HTTP ${response.status})
- ${cfg.label} sign-in did not return a poll id
- ChatGPT token response was missing access_token or refresh_t
- ChatGPT did not return a complete device code
AI-assisted analysis of odysseus-dev/odysseus@f9235ebbf1 (2026-08-14).
Data as JSON: /api/errors/ddd20691cc277ea8.
Report an issue: GitHub.