{"record":{"id":"145f9920340e97da","repo":"farion1231/cc-switch","slug":"provider-key-is-required-for-appid","errorCode":null,"errorMessage":"Provider key is required for ${appId}","messagePattern":"Provider key is required for (.+?)","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/lib/query/mutations.ts","lineNumber":77,"sourceCode":"      }\n\n      let id: string;\n\n      if (\n        appId === \"opencode\" ||\n        appId === \"openclaw\" ||\n        appId === \"hermes\" ||\n        appId === \"pi\"\n      ) {\n        if (\n          providerInput.category === \"omo\" ||\n          providerInput.category === \"omo-slim\"\n        ) {\n          const prefix = providerInput.category === \"omo\" ? \"omo\" : \"omo-slim\";\n          id = `${prefix}-${generateUUID()}`;\n        } else {\n          if (!providerInput.providerKey) {\n            throw new Error(`Provider key is required for ${appId}`);\n          }\n          id = providerInput.providerKey;\n        }\n      } else {\n        id = generateUUID();\n      }\n\n      const newProvider: Provider = {\n        ...rest,\n        id,\n        createdAt: Date.now(),\n      };\n      delete (newProvider as any).providerKey;\n\n      await providersApi.add(newProvider, appId, addToLive);\n      return newProvider;\n    },\n    onSuccess: async () => {","sourceCodeStart":59,"sourceCodeEnd":95,"githubUrl":"https://github.com/farion1231/cc-switch/blob/0b5da510168914b251481654a568c3ffacd62cf4/src/lib/query/mutations.ts#L59-L95","documentation":"In createProvider, the appIds opencode/openclaw/hermes/pi derive the new provider's stable ID from providerInput.providerKey, unless category is 'omo' or 'omo-slim' (which get a prefixed generated UUID). For any other category on those apps a falsy providerKey aborts with 'Provider key is required for <appId>' before the Provider object is built. All other appIds fall through to generateUUID() and never reach this branch.","triggerScenarios":"createProvider({ appId: 'opencode', providerInput: { category: 'custom', providerKey: '' } }) — a preset-driven form that failed to attach a providerKey, or a hand-built/test mutation call.","commonSituations":"Custom-provider form submitted without selecting a preset (the preset normally supplies the key); an import path that dropped providerKey; calling the mutation directly in tests.","solutions":["Supply providerInput.providerKey (e.g. 'anthropic', 'openrouter') when creating providers on opencode/openclaw/hermes/pi","Or set category to 'omo'/'omo-slim' so the mutation generates a prefixed UUID id instead","Gate the form's submit action on a non-empty provider key so the mutation never fires incomplete"],"exampleFix":"// before\ncreateProvider({\n  appId: 'opencode',\n  providerInput: { category: 'custom', providerKey: '' },\n});\n\n// after\ncreateProvider({\n  appId: 'opencode',\n  providerInput: { category: 'custom', providerKey: 'anthropic' },\n});","handlingStrategy":"validation","validationCode":"const NEEDS_PROVIDER_KEY = new Set(['opencode', 'openclaw', 'hermes', 'pi']);\nconst needsKey =\n  NEEDS_PROVIDER_KEY.has(appId) &&\n  providerInput.category !== 'omo' &&\n  providerInput.category !== 'omo-slim';\nif (needsKey && !providerInput.providerKey?.trim()) {\n  // block submit: show \"select a preset / enter provider key\"\n}","typeGuard":null,"tryCatchPattern":"try {\n  await createProvider({ appId, providerInput });\n} catch (error) {\n  if (error instanceof Error && error.message.startsWith('Provider key is required')) {\n    // focus the preset/key selector in the form\n  } else {\n    throw error;\n  }\n}","preventionTips":["Disable submit until a preset (or explicit provider key) is chosen on those appIds","Default new custom providers to category 'omo' if a generated id is acceptable","Assert providerKey presence in tests that build providerInput by hand"],"tags":["providers","validation","mutation","required-field"],"backgroundTag":"missing-required-argument","analyzedSha":"0b5da510168914b251481654a568c3ffacd62cf4","analyzedAt":"2026-08-20T14:29:00.113Z","contentChangedAt":"2026-08-20T14:29:00.113Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}