{"record":{"id":"ffb42246d1e30597","repo":"wavetermdev/waveterm","slug":"block-not-found-s","errorCode":null,"errorMessage":"block not found: %s","messagePattern":"block not found: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/jobcontroller/jobcontroller.go","lineNumber":177,"sourceCode":"\n\tvar statuses []*wshrpc.JobManagerStatusUpdate\n\tfor _, job := range allJobs {\n\t\tstatuses = append(statuses, &wshrpc.JobManagerStatusUpdate{\n\t\t\tJobId:            job.OID,\n\t\t\tJobManagerStatus: job.JobManagerStatus,\n\t\t})\n\t}\n\n\treturn statuses, nil\n}\n\nfunc GetBlockJobStatus(ctx context.Context, blockId string) (*wshrpc.BlockJobStatusData, error) {\n\tblock, err := wstore.DBGet[*waveobj.Block](ctx, blockId)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to get block: %w\", err)\n\t}\n\tif block == nil {\n\t\treturn nil, fmt.Errorf(\"block not found: %s\", blockId)\n\t}\n\n\tdata := &wshrpc.BlockJobStatusData{\n\t\tBlockId:   blockId,\n\t\tVersionTs: blockJobStatusVersion.GetVersionTs(),\n\t}\n\n\tif block.JobId == \"\" {\n\t\treturn data, nil\n\t}\n\n\tjob, err := wstore.DBGet[*waveobj.Job](ctx, block.JobId)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to get job: %w\", err)\n\t}\n\tif job == nil {\n\t\treturn data, nil\n\t}","sourceCodeStart":159,"sourceCodeEnd":195,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/pkg/jobcontroller/jobcontroller.go#L159-L195","documentation":"GetBlockJobStatus returns this error when wstore.DBGet successfully completes but returns a nil block, meaning no waveobj.Block exists with the given blockId. It is a caller-supplied-identifier problem, not a storage failure.","triggerScenarios":"Calling GetBlockJobStatus (or BlockJobStatusCommand / SendBlockJobStatusEvent) with a blockId that does not exist in wstore — stale block reference, block already closed/deleted, or a typo'd/fabricated ID.","commonSituations":"Frontend caches a blockId after the block was closed; event races where the block is deleted between enqueue and lookup; passing an OID of the wrong object type.","solutions":["Verify the blockId is a valid existing block OID before calling","Check whether the block was closed/deleted and re-create it if needed","Use a live BlockId from the current block registry","Treat as expected when handling delete/close races and skip silently"],"exampleFix":"// before\nstatus, err := jobcontroller.GetBlockJobStatus(ctx, staleBlockId)\nif err != nil {\n\treturn err\n}\n// after\nstatus, err := jobcontroller.GetBlockJobStatus(ctx, blockId)\nif err != nil && strings.HasPrefix(err.Error(), \"block not found\") {\n\treturn nil // block closed; nothing to report\n} else if err != nil {\n\treturn err\n}","handlingStrategy":"validation","validationCode":"block, err := wstore.DBGet[*waveobj.Block](ctx, blockId)\nif block == nil {\n\treturn fmt.Errorf(\"skip: block %s does not exist\", blockId)\n}\n_ = err","typeGuard":"func isBlockNotFoundErr(err error) bool {\n\treturn err != nil && strings.Contains(err.Error(), \"block not found\")\n}","tryCatchPattern":"status, err := jobcontroller.GetBlockJobStatus(ctx, blockId)\nif err != nil {\n\tif isBlockNotFoundErr(err) {\n\t\treturn nil // expected race: block closed\n\t}\n\treturn err\n}","preventionTips":["Validate blockId against the current block registry before calls","Handle close/delete races gracefully (not-found is expected)","Never pass OIDs of other object types as blockId","Clean up pending work when a block is closed"],"tags":["not-found","block","job-controller"],"backgroundTag":"record-not-found","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}