{"record":{"id":"593feced40f4b69a","repo":"derailed/k9s","slug":"expecting-a-switchable-resource","errorCode":null,"errorMessage":"expecting a switchable resource","messagePattern":"expecting a switchable resource","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/view/command.go","lineNumber":202,"sourceCode":"\tif comd != nil {\n\t\tp.Merge(comd)\n\t}\n\n\tif context, ok := p.HasContext(); ok {\n\t\tif context != c.app.Config.ActiveContextName() {\n\t\t\tif err := c.app.Config.Save(true); err != nil {\n\t\t\t\tslog.Error(\"Config save failed during command exec\", slogs.Error, err)\n\t\t\t} else {\n\t\t\t\tslog.Debug(\"Successfully saved config\", slogs.Context, context)\n\t\t\t}\n\t\t}\n\t\tres, err := dao.AccessorFor(c.app.factory, client.CtGVR)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tswitcher, ok := res.(dao.Switchable)\n\t\tif !ok {\n\t\t\treturn errors.New(\"expecting a switchable resource\")\n\t\t}\n\t\tif err := switcher.Switch(context); err != nil {\n\t\t\tslog.Error(\"Unable to switch context\", slogs.Error, err)\n\t\t\treturn err\n\t\t}\n\t\tif err := c.app.switchContext(p, false); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tns := c.app.Config.ActiveNamespace()\n\tif cns, ok := p.NSArg(); ok {\n\t\tns = cns\n\t}\n\tif ok, err := dao.MetaAccess.IsNamespaced(gvr); ok && err == nil {\n\t\tif err := c.app.switchNS(ns); err != nil {\n\t\t\treturn err\n\t\t}","sourceCodeStart":184,"sourceCodeEnd":220,"githubUrl":"https://github.com/derailed/k9s/blob/2d3ccc6ba2ce98c3781bfc441bb3e884f072774f/internal/view/command.go#L184-L220","documentation":"Returned by the context-switch path in `Command.execCmd` (internal/view/command.go:~202). It fetches the DAO for `client.CtGVR` (contexts resource) via `dao.AccessorFor` and type-asserts it to `dao.Switchable`. In stock k9s the registered contexts DAO always implements Switchable (it calls the config switch API), so this error is an internal invariant failure: the factory returned an accessor that cannot switch contexts.","triggerScenarios":"`dao.AccessorFor(factory, client.CtGVR)` succeeds but the returned accessor does not implement `dao.Switchable` — only possible when factory registration is customized (custom builds, forks, test factories registering a plain DAO for contexts) or the DAO type changed in a fork.","commonSituations":"Forked k9s builds or plugins that override DAO registration for the contexts GVR; unit tests with a mock factory returning a generic accessor; version drift after rebasing a fork on upstream where the contexts DAO interface moved.","solutions":["Restore the stock contexts DAO registration for client.CtGVR in the factory (it must implement dao.Switchable)","On a fork, make your custom contexts accessor implement the Switchable interface (Switch(name) error)","Verify you are not running a test/stub factory in production; check factory init order"],"exampleFix":null,"handlingStrategy":"type-guard","validationCode":null,"typeGuard":"func canSwitch(f dao.Factory, gvr *client.GVR) bool {\n    a, err := dao.AccessorFor(f, gvr)\n    _, ok := a.(dao.Switchable)\n    return err == nil && ok\n}","tryCatchPattern":"if _, ok := res.(dao.Switchable); !ok {\n    return fmt.Errorf(\"expecting a switchable resource for %s\", gvr)\n}","preventionTips":["Keep the stock contexts DAO registered for client.CtGVR","Assert interface compliance at factory init (compile-time check)","Never replace contexts accessor without implementing Switch"],"tags":["kubernetes","context-switch","dao","type-assertion","k9s"],"backgroundTag":null,"analyzedSha":"2d3ccc6ba2ce98c3781bfc441bb3e884f072774f","analyzedAt":"2026-08-15T16:09:14.432Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}