{"record":{"id":"db1a7fbb9c4501bd","repo":"vxcontrol/pentagi","slug":"failed-to-switch-provider-w","errorCode":null,"errorMessage":"failed to switch provider: %w","messagePattern":"failed to switch provider: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"backend/pkg/controller/flow.go","lineNumber":653,"sourceCode":"\n\treturn assistants\n}\n\nfunc (fw *flowWorker) ListTasks(ctx context.Context) []TaskWorker {\n\treturn fw.tc.ListTasks(ctx)\n}\n\nfunc (fw *flowWorker) PutInput(\n\tctx context.Context,\n\tinput string,\n\tprv provider.Provider,\n\tresources []database.UserResource,\n) error {\n\tctx, span := obs.Observer.NewSpan(ctx, obs.SpanKindInternal, \"controller.flowWorker.PutInput\")\n\tdefer span.End()\n\n\tif err := fw.switchProvider(ctx, prv); err != nil {\n\t\treturn fmt.Errorf(\"failed to switch provider: %w\", err)\n\t}\n\n\tif err := fw.PutResources(ctx, resources); err != nil {\n\t\tfw.logger.WithError(err).Warn(\"failed to copy resources before user input\")\n\t}\n\n\tflin := flowInput{input: input, done: make(chan error, 1)}\n\tselect {\n\tcase <-fw.ctx.Done():\n\t\tclose(flin.done)\n\t\treturn fmt.Errorf(\"flow %d stopped: %w\", fw.flowCtx.FlowID, fw.ctx.Err())\n\tcase <-ctx.Done():\n\t\tclose(flin.done)\n\t\treturn fmt.Errorf(\"flow %d input processing timeout: %w\", fw.flowCtx.FlowID, ctx.Err())\n\tcase fw.input <- flin:\n\t\ttimer := time.NewTimer(flowInputTimeout)\n\t\tdefer timer.Stop()\n","sourceCodeStart":635,"sourceCodeEnd":671,"githubUrl":"https://github.com/vxcontrol/pentagi/blob/ea665308baaff015b226f308438a68d929d0f29b/backend/pkg/controller/flow.go#L635-L671","documentation":"PutInput wraps an error from fw.switchProvider(ctx, prv) — the step that reconfigures the flow worker to use the requested LLM provider before processing user input. If the provider cannot be switched (provider unavailable, not configured, or construction fails), the input is rejected and resources are never queued.","triggerScenarios":"Calling PutInput with a provider value that fails switchProvider: the provider name/type is not registered, its API key is missing, the provider adapter failed to initialize, or the provider's credential check errors.","commonSituations":"User selected an LLM provider in the UI that was later removed or whose API key was cleared from settings; typo in provider name passed via REST/GraphQL; provider type not whitelisted in Valid(); environment variable for the provider missing.","solutions":["Read the wrapped error to see whether the provider is unregistered, unconfigured, or rejected credentials.","Verify the provider type is whitelisted in pkg/server/models/providers.go Valid() and registered in pkg/providers/providers.go.","Set the provider's API key/server URL in settings or env (e.g. OPENAI_API_KEY) and retry PutInput.","Validate the provider name before calling PutInput; fall back to the flow's current provider if switching is optional."],"exampleFix":"// before\nerr := fw.PutInput(ctx, \"gpt99-turbo\", input, resources) // unknown provider\n// after\nif provider.IsValid(prv) {\n    err = fw.PutInput(ctx, prv, input, resources)\n} else {\n    err = fmt.Errorf(\"unsupported provider %q\", prv)\n}","handlingStrategy":"validation","validationCode":"func providerConfigured(prv string) error {\n    if !servermodels.ProviderType(prv).Valid() {\n        return fmt.Errorf(\"unsupported provider %q\", prv)\n    }\n    if _, err := providers.GetProvider(prv); err != nil {\n        return fmt.Errorf(\"provider not available: %w\", err)\n    }\n    return nil\n}\n// call before PutInput\nif err := providerConfigured(prv); err != nil { return err }","typeGuard":"func isKnownProvider(prv string) bool {\n    _, err := providers.GetProvider(prv)\n    return err == nil\n}","tryCatchPattern":"if err := fw.PutInput(ctx, prv, input, res); err != nil {\n    if strings.Contains(err.Error(), \"failed to switch provider\") {\n        // fall back to the flow's current provider or surface a config error to the user\n        return fmt.Errorf(\"provider %q unavailable: %w\", prv, err)\n    }\n    return err\n}","preventionTips":["Whitelist provider types in pkg/server/models/providers.go Valid() and register them in providers.go before exposing in the UI.","Keep API keys/server URLs set in settings or env for every selectable provider.","Validate provider name server-side before invoking PutInput.","Hide unconfigured providers from user-facing pickers."],"tags":["go","provider","llm","configuration"],"backgroundTag":"provider-switch-failed","analyzedSha":"ea665308baaff015b226f308438a68d929d0f29b","analyzedAt":"2026-09-01T14:16:31.421Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}