{"record":{"id":"576e264a0bf166e3","repo":"wavetermdev/waveterm","slug":"failed-to-send-input-to-job-w","errorCode":null,"errorMessage":"failed to send input to job: %w","messagePattern":"failed to send input to job: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/jobcontroller/jobcontroller.go","lineNumber":1535,"sourceCode":"\t\t\tlog.Printf(\"[job:%s] warning: failed to update termsize in DB: %v\", jobId, err)\n\t\t}\n\t}\n\n\t_, err := CheckJobConnected(ctx, jobId)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\trpcOpts := &wshrpc.RpcOpts{\n\t\tRoute:      wshutil.MakeJobRouteId(jobId),\n\t\tTimeout:    5000,\n\t\tNoResponse: false,\n\t}\n\n\tbareRpc := wshclient.GetBareRpcClient()\n\terr = wshclient.JobInputCommand(bareRpc, data, rpcOpts)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to send input to job: %w\", err)\n\t}\n\n\treturn nil\n}\n\nfunc resetTerminalState(logCtx context.Context, blockId string) {\n\tif blockId == \"\" {\n\t\treturn\n\t}\n\tctx, cancelFn := context.WithTimeout(context.Background(), DefaultTimeout)\n\tdefer cancelFn()\n\tif isFileEmpty(ctx, blockId) {\n\t\treturn\n\t}\n\tblocklogger.Debugf(logCtx, \"[conndebug] resetTerminalState: resetting terminal state for block\\n\")\n\tresetSeq := shellutil.GetTerminalResetSeq()\n\tresetSeq += \"\\r\\n\"\n\terr := doWFSAppend(ctx, waveobj.MakeORef(waveobj.OType_Block, blockId), JobOutputFileName, []byte(resetSeq))","sourceCodeStart":1517,"sourceCodeEnd":1553,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/pkg/jobcontroller/jobcontroller.go#L1517-L1553","documentation":"This error wraps a failure from wshclient.JobInputCommand, which sends terminal keyboard input to a running background job's PTY over the Wave RPC channel. The library throws it when the RPC round-trip to the job's input endpoint fails (connection issue, job already gone, or underlying PTY write error). It preserves the underlying cause via %w so callers can unwrap it.","triggerScenarios":"Calling the block input path (e.g. user types into a block backed by a job) while the JobController forwards data via JobInputCommand and the RPC returns an error: job not found, RPC timeout, or the job's HandleInput rejecting input (e.g. 'no active process').","commonSituations":"Typing into a terminal block whose underlying process has already exited but whose block is still displayed; the wsh server connection dropped; sending input before the job's PTY is fully initialized.","solutions":["Check the job/block still exists and is running before sending input (poll exit info).","Unwrap the error with errors.Unwrap to see the RPC root cause and fix that (reconnect, restart job).","Retry the input send once after a short delay if it was a transient RPC timeout.","If the process exited, close/relaunch the block instead of sending input."],"exampleFix":"// before\nerr = wshclient.JobInputCommand(bareRpc, data, rpcOpts)\nif err != nil {\n    return fmt.Errorf(\"failed to send input to job: %w\", err)\n}\n// after\nerr = wshclient.JobInputCommand(bareRpc, data, rpcOpts)\nif err != nil {\n    if errors.Is(err, rpcclient.ErrConnectionClosed) {\n        return fmt.Errorf(\"job rpc connection closed, cannot send input: %w\", err)\n    }\n    return fmt.Errorf(\"failed to send input to job: %w\", err)\n}","handlingStrategy":"try-catch","validationCode":"// Go: check the job is still live before sending input\nif exited, _ := jobCmd.GetExitInfo(); exited {\n    return errors.New(\"job already exited; not sending input\")\n}","typeGuard":"func hasActiveProcess(jm *jobmanager.JobCmd) bool {\n    exited, _ := jm.GetExitInfo()\n    return !exited\n}","tryCatchPattern":"err := wshclient.JobInputCommand(bareRpc, data, rpcOpts)\nif err != nil {\n    var rpcErr *rpcclient.RpcError\n    if errors.As(err, &rpcErr) {\n        // reconnect or report job unavailable\n    }\n    return fmt.Errorf(\"failed to send input to job: %w\", err)\n}","preventionTips":["Track job-exited events and stop sending input once fired","Always unwrap the wrapped cause to distinguish connection vs process errors","Debounce input RPCs so stale input isn't delivered after exit"],"tags":["rpc","terminal","pty","input"],"backgroundTag":"rpc-send-input-failed","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}