{"record":{"id":"1539d7febecf0a32","repo":"wavetermdev/waveterm","slug":"failed-to-get-block-w","errorCode":null,"errorMessage":"failed to get block: %w","messagePattern":"failed to get block: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/jobcontroller/jobcontroller.go","lineNumber":174,"sourceCode":"\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to get jobs: %w\", err)\n\t}\n\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}","sourceCodeStart":156,"sourceCodeEnd":192,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/pkg/jobcontroller/jobcontroller.go#L156-L192","documentation":"GetBlockJobStatus first fetches the waveobj.Block for blockId from wstore. This error wraps a DBGet failure for that block — a storage-layer error rather than a missing block (missing is reported separately as 'block not found').","triggerScenarios":"Calling GetBlockJobStatus (directly or via SendBlockJobStatusEvent / BlockJobStatusCommand) when wstore.DBGet[*waveobj.Block] fails — DB I/O error, invalid/corrupted record data, canceled context.","commonSituations":"Querying a block while the DB is shutting down; corrupted block record; context canceled by an RPC timeout.","solutions":["Inspect the wrapped inner error for the wstore cause","Retry with a valid context","Verify the wave DB integrity in the data directory","For event senders, skip sending the event on transient failure"],"exampleFix":"// before\nstatus, err := jobcontroller.GetBlockJobStatus(ctx, blockId)\nif err != nil {\n\tpanic(err)\n}\n// after\nstatus, err := jobcontroller.GetBlockJobStatus(ctx, blockId)\nif err != nil {\n\tlog.Printf(\"block job status unavailable for %s: %v\", blockId, err)\n\treturn\n}","handlingStrategy":"try-catch","validationCode":"if ctx.Err() != nil {\n\treturn errors.New(\"context canceled\")\n}\nif blockId == \"\" {\n\treturn errors.New(\"blockId is empty\")\n}","typeGuard":"func blockExists(ctx context.Context, blockId string) bool {\n\tb, err := wstore.DBGet[*waveobj.Block](ctx, blockId)\n\treturn err == nil && b != nil\n}","tryCatchPattern":"status, err := jobcontroller.GetBlockJobStatus(ctx, blockId)\nif err != nil && !strings.HasPrefix(err.Error(), \"block not found\") {\n\tlog.Printf(\"transient failure for block %s: %v\", blockId, err)\n\treturn\n}","preventionTips":["Check ctx before RPC/db calls","Distinguish not-found from storage failure in handling code","Verify blockId provenance — use live registry IDs","Skip event sends on transient DB failures"],"tags":["database","wstore","block"],"backgroundTag":"database-read-failed","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}