{"record":{"id":"922c8448718680dd","repo":"unslothai/unsloth","slug":"bad-candidate-spec-fragment-part-expected-key","errorCode":null,"errorMessage":"Bad candidate spec fragment '{part}' (expected key=value)","messagePattern":"Bad candidate spec fragment '(.+?)' \\(expected key=value\\)","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"scripts/video_quality.py","lineNumber":270,"sourceCode":"        chunks = [c.to_ndarray() for c in container.decode(container.streams.audio[0])]\n        if chunks:\n            audio = np.concatenate([c.reshape(c.shape[0], -1).mean(axis = 0) for c in chunks])\n    container.close()\n    return frames, audio\n\n\n# ── configuration plumbing ───────────────────────────────────────────────────\n\n\ndef parse_spec(spec: str) -> dict[str, str]:\n    \"\"\"'k=v;k=v' (or space-free 'k=v,k=v') -> dict; empty string -> {} (pure base).\"\"\"\n    out: dict[str, str] = {}\n    for part in spec.replace(\",\", \";\").split(\";\"):\n        part = part.strip()\n        if not part:\n            continue\n        if \"=\" not in part:\n            raise ValueError(f\"Bad candidate spec fragment '{part}' (expected key=value)\")\n        key, value = part.split(\"=\", 1)\n        out[key.strip()] = value.strip()\n    return out\n\n\ndef spec_label(spec: dict[str, str]) -> str:\n    if not spec:\n        return \"base\"\n    return \",\".join(\n        f\"{k}={Path(v).name if k == 'gguf_filename' else v}\" for k, v in sorted(spec.items())\n    )\n\n\ndef run_config(\n    backend: Any, args: Any, spec: dict[str, str], workdir: Path, name: str\n) -> dict[str, Any]:\n    \"\"\"Load per spec, generate the fixed clip, unload. Returns frames/audio/cost.\"\"\"\n    import torch","sourceCodeStart":252,"sourceCodeEnd":288,"githubUrl":"https://github.com/unslothai/unsloth/blob/203007d19051dcd2ae33876786d117c99f6b0368/scripts/video_quality.py#L252-L288","documentation":"Thrown by ensureCodexProvider (chat-providers-dialog.tsx:588-596) when the user triggers ChatGPT OAuth but the resolved provider registry entry's auth_kind is not 'chatgpt_oauth'. The function maps the selected providerType through toExternalBackendProviderType and looks up registryByType; only registry entries explicitly marked auth_kind === 'chatgpt_oauth' (i.e. Codex) can go through the ChatGPT authorization flow. Everything else (api_key providers) is rejected before createProviderConfig runs.","triggerScenarios":"Clicking 'Sign in with ChatGPT' / the OAuth button while providerType is an api-key provider (OpenRouter, Groq, a custom OpenAI-compatible gateway) or an unrecognized type whose registryByType.get(...) returns undefined (entry?.auth_kind is then undefined !== 'chatgpt_oauth').","commonSituations":"UI state desync where the OAuth button renders for a non-OAuth provider type; editing an existing non-Codex provider (editingProviderId set) and invoking the Codex OAuth path; a registry fetch that failed leaving registryByType empty.","solutions":["Switch the connection type to the Codex provider in the dialog before starting ChatGPT authorization.","For api-key providers, enter the API key instead — OAuth does not apply.","If the registry list appears empty or stale, reload the providers dialog so the registry refetches.","As a developer, gate the OAuth button's disabled state on selectedProviderContract?.auth_kind === 'chatgpt_oauth' so the path is unreachable for other types."],"exampleFix":"// before\n<Button onClick={startChatGPTOAuth}>Sign in with ChatGPT</Button>\n\n// after\n<Button disabled={selectedProviderContract?.auth_kind !== \"chatgpt_oauth\"} onClick={startChatGPTOAuth}>Sign in with ChatGPT</Button>","handlingStrategy":"type-guard","validationCode":"const supportsChatGptOAuth = (registryByType: Map<string, ProviderRegistryEntry>, providerType: string): boolean =>\n  registryByType.get(toExternalBackendProviderType(providerType))?.auth_kind === 'chatgpt_oauth';","typeGuard":"function isChatGptOAuthEntry(entry: ProviderRegistryEntry | undefined): entry is ProviderRegistryEntry & { auth_kind: 'chatgpt_oauth' } {\n  return entry?.auth_kind === 'chatgpt_oauth';\n}","tryCatchPattern":"try {\n  await ensureCodexProvider();\n} catch (error) {\n  if (error instanceof Error && error.message === 'This connection does not support ChatGPT authorization.') {\n    toast.info('Switch to the Codex connection to use ChatGPT sign-in.');\n  } else throw error;\n}","preventionTips":["Render the OAuth button only when selectedProviderContract?.auth_kind === 'chatgpt_oauth' (the dialog already tracks usesOAuth this way).","Reset providerType-dependent UI when the user switches connection types.","Treat a missing registry entry as 'OAuth unavailable', not as an error path."],"tags":["oauth","providers","validation","frontend"],"backgroundTag":null,"analyzedSha":"203007d19051dcd2ae33876786d117c99f6b0368","analyzedAt":"2026-08-15T02:48:39.846Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}