{"record":{"id":"f5870756050d6e65","repo":"wavetermdev/waveterm","slug":"durable-shell-controller-requires-a-remote-connect","errorCode":null,"errorMessage":"durable shell controller requires a remote connection","messagePattern":"durable shell controller requires a remote connection","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/blockcontroller/durableshellcontroller.go","lineNumber":146,"sourceCode":"}\n\n// Start initializes or reconnects to a durable shell for the block.\n// Logic:\n// - If block has no existing jobId: starts a new job and attaches it\n// - If block has existing jobId with running job manager: reconnects to existing job\n// - If block has existing jobId with non-running job manager:\n//   - force=true: detaches old job and starts new one\n//   - force=false: returns without starting (leaves block unstarted)\n//\n// After establishing jobId, ensures job connection is active (reconnects if needed)\nfunc (dsc *DurableShellController) Start(ctx context.Context, blockMeta waveobj.MetaMapType, rtOpts *waveobj.RuntimeOpts, force bool) error {\n\tblockData, err := wstore.DBMustGet[*waveobj.Block](ctx, dsc.BlockId)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error getting block: %w\", err)\n\t}\n\n\tif conncontroller.IsLocalConnName(dsc.ConnName) {\n\t\treturn fmt.Errorf(\"durable shell controller requires a remote connection\")\n\t}\n\n\tvar jobId string\n\tif blockData.JobId != \"\" {\n\t\tstatus, err := jobcontroller.GetJobManagerStatus(ctx, blockData.JobId)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error getting job manager status: %w\", err)\n\t\t}\n\t\tif status == jobcontroller.JobManagerStatus_Running {\n\t\t\tjobId = blockData.JobId\n\t\t} else if !force {\n\t\t\tlog.Printf(\"block %q has jobId %s but manager is not running (status: %s), not starting (force=false)\\n\", dsc.BlockId, blockData.JobId, status)\n\t\t\treturn nil\n\t\t} else {\n\t\t\tlog.Printf(\"block %q has jobId %s but manager is not running (status: %s), starting new job (force=true)\\n\", dsc.BlockId, blockData.JobId, status)\n\t\t\t// intentionally leave jobId empty to trigger starting a new job below\n\t\t}\n\t}","sourceCodeStart":128,"sourceCodeEnd":164,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/pkg/blockcontroller/durableshellcontroller.go#L128-L164","documentation":"Durable shells rely on remote job management for persistence across restarts, so Start refuses to run when dsc.ConnName is a local connection. This error is a guard against starting a durable shell controller on a local terminal block.","triggerScenarios":"Start is invoked with the controller constructed with ConnName set to a local connection name (IsLocalConnName true), typically because the block's meta connection was cleared or set to local.","commonSituations":"User switched a terminal block from a remote connection back to local while a durable shell controller was still wired up; block created locally but durable-shell code path triggered by config; meta.connection removed.","solutions":["Set the block's connection to a remote SSH profile in block settings before using durable shell","Use a regular (non-durable) shell controller for local terminals","Verify meta.connection is populated with a remote conn name at controller construction time"],"exampleFix":"// before\n\"meta\": { \"connection\": \"\" } // local -> durable shell refuses\n// after\n\"meta\": { \"connection\": \"conn:myprofile\" } // remote profile","handlingStrategy":"validation","validationCode":"if conncontroller.IsLocalConnName(connName) {\n    // use a plain shell controller, not DurableShellController\n}","typeGuard":null,"tryCatchPattern":"if err := dsc.Start(ctx, meta, rtOpts, true); err != nil {\n    if strings.Contains(err.Error(), \"requires a remote connection\") { /* fall back to local controller */ }\n}","preventionTips":["Pick controller type based on meta.connection before starting","Don't convert remote terminal blocks to local while durable controllers are active","Document that durable shell is remote-only"],"tags":["configuration","durable-shell","local-connection","wave-terminal"],"backgroundTag":"durable-shell-requires-remote","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}