{"record":{"id":"0042bebb288a001b","repo":"wavetermdev/waveterm","slug":"unknown-controller-type-q","errorCode":null,"errorMessage":"unknown controller type %q","messagePattern":"unknown controller type %q","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/blockcontroller/blockcontroller.go","lineNumber":260,"sourceCode":"\tif existing != nil {\n\t\tcontroller = existing\n\t} else {\n\t\t// Create new controller based on type\n\t\tswitch controllerName {\n\t\tcase BlockController_Shell, BlockController_Cmd:\n\t\t\tif shouldUseDurableShellController {\n\t\t\t\tcontroller = MakeDurableShellController(tabId, blockId, controllerName, connName)\n\t\t\t} else {\n\t\t\t\tcontroller = MakeShellController(tabId, blockId, controllerName, connName)\n\t\t\t}\n\t\t\tregisterController(blockId, controller)\n\n\t\tcase BlockController_Tsunami:\n\t\t\tcontroller = MakeTsunamiController(tabId, blockId, connName)\n\t\t\tregisterController(blockId, controller)\n\n\t\tdefault:\n\t\t\treturn fmt.Errorf(\"unknown controller type %q\", controllerName)\n\t\t}\n\t}\n\n\t// Check if we need to start/restart\n\tstatus := controller.GetRuntimeStatus()\n\tif status.ShellProcStatus == Status_Init {\n\t\t// For shell/cmd, check connection status first (for non-local connections)\n\t\tif controllerName == BlockController_Shell || controllerName == BlockController_Cmd {\n\t\t\tif !conncontroller.IsLocalConnName(connName) {\n\t\t\t\terr = CheckConnStatus(blockId)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"cannot start shellproc: %w\", err)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Start controller\n\t\terr = controller.Start(ctx, blockData.Meta, rtOpts, force)","sourceCodeStart":242,"sourceCodeEnd":278,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/pkg/blockcontroller/blockcontroller.go#L242-L278","documentation":"ResyncController determines the controller type from the block's meta key 'controller' (MetaKey_Controller). If that value does not match any known controller type (shell, cmd, tsunami, etc.), the default branch returns 'unknown controller type %q'. The block meta contains a controller name the registry does not implement.","triggerScenarios":"A block whose meta[\"controller\"] is set to a string not among the BlockController_* constants — e.g. misspelled value, controller removed/renamed in a version change, or meta written by a newer/older version.","commonSituations":"Manually editing block meta; restoring a workspace DB written by a different Wave version that supported other controller types; plugin/extension writing custom controller names.","solutions":["Inspect blockData.Meta and reset the 'controller' key to a supported value like \"shell\" or \"cmd\"","Update Wave to the version that supports the controller type in the meta","Migrate/normalize block meta when restoring DBs from different versions","Quote the error output (%q) to see exactly which name is stored"],"exampleFix":"// before\nmeta: { \"controller\": \"sheell\" }\n// after\nmeta: { \"controller\": \"shell\" }","handlingStrategy":"validation","validationCode":"allowed := map[string]bool{\"shell\": true, \"cmd\": true, \"tsunami\": true}\nif !allowed[blockData.Meta.GetString(\"controller\", \"\")] { /* fix meta before resync */ }","typeGuard":null,"tryCatchPattern":"if err := ResyncController(ctx, tabId, blockId, rtOpts, false); err != nil && strings.Contains(err.Error(), \"unknown controller type\") {\n    // repair meta['controller'] then retry\n}","preventionTips":["Only write BlockController_* constants into block meta","Run meta migrations when upgrading between versions","Avoid manual DB/meta edits"],"tags":["configuration","meta","blockcontroller"],"backgroundTag":"unknown-controller-type","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}