wavetermdev/waveterm · error

unknown controller type %q

Error message

unknown controller type %q

What it means

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.

Source

Thrown at pkg/blockcontroller/blockcontroller.go:260

	if existing != nil {
		controller = existing
	} else {
		// Create new controller based on type
		switch controllerName {
		case BlockController_Shell, BlockController_Cmd:
			if shouldUseDurableShellController {
				controller = MakeDurableShellController(tabId, blockId, controllerName, connName)
			} else {
				controller = MakeShellController(tabId, blockId, controllerName, connName)
			}
			registerController(blockId, controller)

		case BlockController_Tsunami:
			controller = MakeTsunamiController(tabId, blockId, connName)
			registerController(blockId, controller)

		default:
			return fmt.Errorf("unknown controller type %q", controllerName)
		}
	}

	// Check if we need to start/restart
	status := controller.GetRuntimeStatus()
	if status.ShellProcStatus == Status_Init {
		// For shell/cmd, check connection status first (for non-local connections)
		if controllerName == BlockController_Shell || controllerName == BlockController_Cmd {
			if !conncontroller.IsLocalConnName(connName) {
				err = CheckConnStatus(blockId)
				if err != nil {
					return fmt.Errorf("cannot start shellproc: %w", err)
				}
			}
		}

		// Start controller
		err = controller.Start(ctx, blockData.Meta, rtOpts, force)

View on GitHub (pinned to a4447c1563)

Solutions

  1. Inspect blockData.Meta and reset the 'controller' key to a supported value like "shell" or "cmd"
  2. Update Wave to the version that supports the controller type in the meta
  3. Migrate/normalize block meta when restoring DBs from different versions
  4. Quote the error output (%q) to see exactly which name is stored

Example fix

// before
meta: { "controller": "sheell" }
// after
meta: { "controller": "shell" }
Defensive patterns

Strategy: validation

Validate before calling

allowed := map[string]bool{"shell": true, "cmd": true, "tsunami": true}
if !allowed[blockData.Meta.GetString("controller", "")] { /* fix meta before resync */ }

Try / catch

if err := ResyncController(ctx, tabId, blockId, rtOpts, false); err != nil && strings.Contains(err.Error(), "unknown controller type") {
    // repair meta['controller'] then retry
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01). Data as JSON: /api/errors/0042bebb288a001b. Report an issue: GitHub.