{"record":{"id":"53c8445fd96a9bec","repo":"wavetermdev/waveterm","slug":"api-type-mismatch-chat-has-s-chatopts-has-s-53c844","errorCode":null,"errorMessage":"API type mismatch: chat has %s, chatOpts has %s","messagePattern":"API type mismatch: chat has (.+?), chatOpts has (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/aiusechat/openai/openai-backend.go","lineNumber":481,"sourceCode":"func RunOpenAIChatStep(\n\tctx context.Context,\n\tsse *sse.SSEHandlerCh,\n\tchatOpts uctypes.WaveChatOpts,\n\tcont *uctypes.WaveContinueResponse,\n) (*uctypes.WaveStopReason, []*OpenAIChatMessage, *uctypes.RateLimitInfo, error) {\n\tif sse == nil {\n\t\treturn nil, nil, nil, errors.New(\"sse handler is nil\")\n\t}\n\n\t// Get chat from store\n\tchat := chatstore.DefaultChatStore.Get(chatOpts.ChatId)\n\tif chat == nil {\n\t\treturn nil, nil, nil, fmt.Errorf(\"chat not found: %s\", chatOpts.ChatId)\n\t}\n\n\t// Validate that chatOpts.Config match the chat's stored configuration\n\tif chat.APIType != chatOpts.Config.APIType {\n\t\treturn nil, nil, nil, fmt.Errorf(\"API type mismatch: chat has %s, chatOpts has %s\", chat.APIType, chatOpts.Config.APIType)\n\t}\n\tif !uctypes.AreModelsCompatible(chat.APIType, chat.Model, chatOpts.Config.Model) {\n\t\treturn nil, nil, nil, fmt.Errorf(\"model mismatch: chat has %s, chatOpts has %s\", chat.Model, chatOpts.Config.Model)\n\t}\n\tif chat.APIVersion != chatOpts.Config.APIVersion {\n\t\treturn nil, nil, nil, fmt.Errorf(\"API version mismatch: chat has %s, chatOpts has %s\", chat.APIVersion, chatOpts.Config.APIVersion)\n\t}\n\n\t// Context with timeout if provided.\n\tif chatOpts.Config.TimeoutMs > 0 {\n\t\tvar cancel context.CancelFunc\n\t\tctx, cancel = context.WithTimeout(ctx, time.Duration(chatOpts.Config.TimeoutMs)*time.Millisecond)\n\t\tdefer cancel()\n\t}\n\n\t// Validate continuation if provided\n\tif cont != nil {\n\t\tif !uctypes.AreModelsCompatible(chat.APIType, chatOpts.Config.Model, cont.Model) {","sourceCodeStart":463,"sourceCodeEnd":499,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/pkg/aiusechat/openai/openai-backend.go#L463-L499","documentation":"RunOpenAIChatStep validates that chatOpts.Config matches the configuration persisted with the chat. \"API type mismatch\" is returned at openai-backend.go:481 when chat.APIType differs from chatOpts.Config.APIType — the caller is trying to run a chat step with a different provider/API kind (e.g. openai vs azure openai) than the chat was created with.","triggerScenarios":"Passing chatOpts whose Config.APIType differs from the stored chat's APIType — e.g. reusing a chat id across a provider switch, copying options from another chat, or hardcoding APIType instead of reading it from the chat.","commonSituations":"User flips the AI provider setting mid-conversation and the client keeps the old ChatId; automation scripts building WaveChatOpts by hand; migrating from OpenAI to Azure OpenAI without starting a new chat.","solutions":["Use the chat's stored APIType: read chat.APIType and set chatOpts.Config.APIType accordingly before stepping","Start a new chat with the new API type instead of continuing the existing one","If the provider switch is intentional, migrate/convert the chat history into a chat registered with the new API type","Log both values in the error message when debugging to confirm which side is stale"],"exampleFix":"// before\nchatOpts.Config.APIType = \"openai\" // hardcoded\nRunOpenAIChatStep(ctx, sse, chatOpts, nil)\n// after\nchat := chatstore.DefaultChatStore.Get(chatOpts.ChatId)\nchatOpts.Config.APIType = chat.APIType // match stored config\nRunOpenAIChatStep(ctx, sse, chatOpts, nil)","handlingStrategy":"validation","validationCode":"chat := chatstore.DefaultChatStore.Get(chatOpts.ChatId)\nif chat != nil && chat.APIType != chatOpts.Config.APIType {\n    chatOpts.Config.APIType = chat.APIType // or start a new chat\n}","typeGuard":"func apiTypeMatches(chatOpts uctypes.WaveChatOpts) bool {\n    chat := chatstore.DefaultChatStore.Get(chatOpts.ChatId)\n    return chat != nil && chat.APIType == chatOpts.Config.APIType\n}","tryCatchPattern":"if _, _, _, err := RunOpenAIChatStep(ctx, sse, chatOpts, nil); err != nil {\n    if strings.HasPrefix(err.Error(), \"API type mismatch\") {\n        // rebuild opts from stored chat config or start a new chat\n        return nil\n    }\n    return err\n}","preventionTips":["Derive Config from the stored chat, never hardcode APIType","Start a new chat when the user switches providers","Keep provider settings immutable for the lifetime of a chat","Log both stored and provided values when this error appears"],"tags":["go","configuration","openai","api-type"],"backgroundTag":"configuration-mismatch","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}