{"record":{"id":"07b5a746c1e3d873","repo":"wavetermdev/waveterm","slug":"failed-to-attach-job-to-block-w","errorCode":null,"errorMessage":"failed to attach job to block: %w","messagePattern":"failed to attach job to block: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/jobcontroller/jobcontroller.go","lineNumber":673,"sourceCode":"\t\tCmdArgs:          params.Args,\n\t\tCmdEnv:           params.Env,\n\t\tCmdTermSize:      *params.TermSize,\n\t\tJobAuthToken:     jobAuthToken,\n\t\tJobManagerStatus: JobManagerStatus_Init,\n\t\tAttachedBlockId:  params.BlockId,\n\t\tWaveVersion:      wavebase.WaveVersion,\n\t\tMeta:             make(waveobj.MetaMapType),\n\t}\n\n\terr = wstore.DBInsert(ctx, job)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"failed to create job in database: %w\", err)\n\t}\n\tif params.BlockId != \"\" {\n\t\t// AttachJobToBlock will send status\n\t\terr = AttachJobToBlock(ctx, jobId, params.BlockId)\n\t\tif err != nil {\n\t\t\treturn \"\", fmt.Errorf(\"failed to attach job to block: %w\", err)\n\t\t}\n\t}\n\tbareRpc := wshclient.GetBareRpcClient()\n\tbroker := bareRpc.StreamBroker\n\treaderRouteId := wshclient.GetBareRpcClientRouteId()\n\twriterRouteId := wshutil.MakeJobRouteId(jobId)\n\treader, streamMeta := broker.CreateStreamReader(readerRouteId, writerRouteId, DefaultStreamRwnd)\n\tjobStreamIds.Set(jobId, streamMeta.Id)\n\n\tfileOpts := wshrpc.FileOpts{\n\t\tMaxSize:  10 * 1024 * 1024,\n\t\tCircular: true,\n\t}\n\terr = filestore.WFS.MakeFile(ctx, jobId, JobOutputFileName, wshrpc.FileMeta{}, fileOpts)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"failed to create WaveFS file: %w\", err)\n\t}\n","sourceCodeStart":655,"sourceCodeEnd":691,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/pkg/jobcontroller/jobcontroller.go#L655-L691","documentation":"If params.BlockId is set, StartJob attaches the new job to that block via AttachJobToBlock (which also sends status); failure is wrapped with this message. It means the target block could not be found, loaded, or updated to reference the job.","triggerScenarios":"Calling StartJob with a BlockId that does not exist, was deleted, or whose backing objects cannot be read/updated in wstore.","commonSituations":"Stale BlockId captured before the block/tab/window was closed, race where the UI closed the block while the job was starting, invalid BlockId passed programmatically.","solutions":["Verify the BlockId refers to an existing, open block before calling StartJob.","Retry with a fresh BlockId obtained from the current UI state.","If the job does not need a terminal block, omit BlockId entirely (it is optional)."],"exampleFix":"// before\njobId, err := jobcontroller.StartJob(ctx, jobcontroller.StartJobParams{BlockId: staleBlockId, ...})\n// after\nblock, err := wstore.DBGet[*waveobj.Block](ctx, staleBlockId)\nif err != nil { staleBlockId = \"\" } // start without attaching\njobId, err := jobcontroller.StartJob(ctx, jobcontroller.StartJobParams{BlockId: staleBlockId, ...})","handlingStrategy":"validation","validationCode":"if params.BlockId != \"\" {\n    if _, err := wstore.DBGet[*waveobj.Block](ctx, params.BlockId); err != nil {\n        params.BlockId = \"\" // block gone; start job unattached instead of failing\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Fetch BlockId from live block state right before starting the job, not from cached references.","Treat BlockId as optional and degrade gracefully to unattached jobs.","Re-resolve block ids after window/tab close events."],"tags":["blocks","wstore","jobcontroller"],"backgroundTag":"block-not-found","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}