{"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":111,"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":93,"sourceCodeEnd":129,"githubUrl":"https://github.com/farion1231/cc-switch/blob/a2e22f330273a5b6ffa87cb8b82b624601bac562/src/lib/query/mutations.ts#L93-L129","documentation":"Thrown inside useAddProviderMutation's mutationFn for appId 'opencode', 'openclaw', 'hermes', or 'pi' when category is not 'omo'/'omo-slim' and providerKey is empty. For these apps the providerKey IS the persisted provider id (it must match the key in the target app's own config, e.g. opencode providers.json), so it cannot be auto-generated like a UUID.","triggerScenarios":"mutateAsync({ appId: 'opencode', providerInput: { category: 'custom', providerKey: '' } }) - any non-omo category with a missing or whitespace-only providerKey on those four app ids.","commonSituations":"A provider form that forgets to carry the key field; importing providers from apps that use generated UUID ids; trimmed empty key slipping through.","solutions":["Supply a providerKey matching the target app's provider key (e.g. 'anthropic', 'my-proxy')","Or set category to 'omo'/'omo-slim', which auto-generates a prefixed UUID id instead","Trim and require the key in the form before submitting the mutation"],"exampleFix":"// before\naddProvider.mutateAsync({ appId: \"opencode\", providerInput: { category: \"custom\", name: \"My proxy\" } });\n\n// after\naddProvider.mutateAsync({ appId: \"opencode\", providerInput: { category: \"custom\", providerKey: \"my-proxy\", name: \"My proxy\" } });","handlingStrategy":"validation","validationCode":"const KEYED_APPS = new Set([\"opencode\", \"openclaw\", \"hermes\", \"pi\"]);\n\nfunction requiresProviderKey(appId: string, category?: string): boolean {\n  return (\n    KEYED_APPS.has(appId) &&\n    category !== \"omo\" &&\n    category !== \"omo-slim\"\n  );\n}\n\nif (requiresProviderKey(appId, input.category) && !input.providerKey?.trim()) {\n  setFormError(\"Provider key is required for this app\");\n  return;\n}","typeGuard":"function isKeyedProviderInput(\n  i: { category?: string; providerKey?: string },\n): i is { category: string; providerKey: string } {\n  return Boolean(i.providerKey && i.providerKey.trim().length > 0);\n}","tryCatchPattern":"try {\n  await addProvider.mutateAsync(input);\n} catch (e) {\n  if (e instanceof Error && e.message.startsWith(\"Provider key is required\")) {\n    focusProviderKeyField();\n  } else {\n    throw e;\n  }\n}","preventionTips":["Make providerKey a required form field for opencode/openclaw/hermes/pi","Disable submit until the key is non-empty","Remember only omo and omo-slim categories are exempt from the key requirement"],"tags":["provider","validation","mutation","opencode"],"backgroundTag":null,"analyzedSha":"a2e22f330273a5b6ffa87cb8b82b624601bac562","analyzedAt":"2026-08-16T03:46:07.889Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}