wavetermdev/waveterm · error
unknown controller type %q
Error message
unknown controller type %q
What it means
Returned when ShellController.ControllerType is neither the controller type handled by createCmdStrAndOpts nor any known branch in setupAndStartShellProcess. It is an internal invariant violation: the block's controller was created with an unrecognized type value.
Source
Thrown at pkg/blockcontroller/shellcontroller.go:421
cmdOpts.Interactive = true
cmdOpts.Login = true
cmdOpts.Cwd = blockMeta.GetString(waveobj.MetaKey_CmdCwd, "")
if cmdOpts.Cwd != "" {
cwdPath, err := wavebase.ExpandHomeDir(cmdOpts.Cwd)
if err != nil {
return nil, err
}
cmdOpts.Cwd = cwdPath
}
} else if bc.ControllerType == BlockController_Cmd {
var cmdOptsPtr *shellexec.CommandOptsType
cmdStr, cmdOptsPtr, err = createCmdStrAndOpts(bc.BlockId, blockMeta, remoteName)
if err != nil {
return nil, err
}
cmdOpts = *cmdOptsPtr
} else {
return nil, fmt.Errorf("unknown controller type %q", bc.ControllerType)
}
var shellProc *shellexec.ShellProc
swapToken := makeSwapToken(ctx, logCtx, bc.BlockId, blockMeta, remoteName, connUnion.ShellType)
cmdOpts.SwapToken = swapToken
blocklogger.Debugf(logCtx, "[conndebug] created swaptoken: %s\n", swapToken.Token)
if connUnion.ConnType == ConnType_Wsl {
wslConn := connUnion.WslConn
if !connUnion.WshEnabled {
shellProc, err = shellexec.StartWslShellProcNoWsh(ctx, rc.TermSize, cmdStr, cmdOpts, wslConn)
if err != nil {
return nil, err
}
} else {
sockName := wslConn.GetDomainSocketName()
rpcContext := wshrpc.RpcContext{
ProcRoute: true,
SockName: sockName,
BlockId: bc.BlockId,View on GitHub (pinned to a4447c1563)
Solutions
- Delete and re-create the terminal block so a fresh ShellController is built with a valid ControllerType
- Upgrade/downgrade so app version matches the workspace/session data version
- Inspect the saved block state and correct ControllerType to a supported value
- Report as a bug if a stock terminal block reproduces this — it indicates state corruption
Example fix
// before: stale restored block with unknown ControllerType reused as-is
shellProc, err := bc.setupAndStartShellProcess(logCtx, rc, blockMeta)
// after: recreate the block controller if type is unknown
if !isKnownControllerType(bc.ControllerType) {
controller = controllerRegistry.Recreate(bc.BlockId)
} Defensive patterns
Strategy: type-guard
Type guard
func knownControllerType(t ControllerType) bool {
switch t {
case ControllerType_Shell:
return true
default:
return false
}
}
// guard: if !knownControllerType(bc.ControllerType) { recreate block controller } Try / catch
proc, err := bc.setupAndStartShellProcess(logCtx, rc, blockMeta)
if err != nil && strings.Contains(err.Error(), "unknown controller type") {
// recreate the block/controller and retry once
} Prevention
- Migrate legacy ControllerType values when loading saved state from older versions
- Re-create suspect blocks instead of reusing restored controller objects
- Keep app and workspace state versions aligned
When it happens
Trigger: DoRunShellCommand invoked on a ShellController whose bc.ControllerType holds an unexpected/legacy/empty value so the if/else chain falls through to the final else.
Common situations: Session data restored from an older Wave version with a deprecated controller type; corrupted block metadata in the workspace state; a plugin or experimental build writing a custom ControllerType.
Related errors
- error formatting metadata: %v
- unknown connection type for conn %q: %s
- unexpected version format: %s
- invalid special wave argument type %s
AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01).
Data as JSON: /api/errors/3f3d80a825ea5ec1.
Report an issue: GitHub.