{"record":{"id":"1ede841900f19499","repo":"wavetermdev/waveterm","slug":"error-getting-block-w-1ede84","errorCode":null,"errorMessage":"error getting block: %w","messagePattern":"error getting block: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/wcore/block.go","lineNumber":160,"sourceCode":"\t\t\tParentORef:  waveobj.MakeORef(waveobj.OType_Tab, tabId).String(),\n\t\t\tRuntimeOpts: rtOpts,\n\t\t\tMeta:        blockDef.Meta,\n\t\t}\n\t\twstore.DBInsert(tx.Context(), blockData)\n\t\ttab.BlockIds = append(tab.BlockIds, blockId)\n\t\twstore.DBUpdate(tx.Context(), tab)\n\t\treturn blockData, nil\n\t})\n}\n\n// Must delete all blocks individually first.\n// Also deletes LayoutState.\n// recursive: if true, will recursively close parent tab, window, workspace, if they are empty.\n// Returns new active tab id, error.\nfunc DeleteBlock(ctx context.Context, blockId string, recursive bool) error {\n\tblock, err := wstore.DBGet[*waveobj.Block](ctx, blockId)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error getting block: %w\", err)\n\t}\n\tif block == nil {\n\t\treturn nil\n\t}\n\tif len(block.SubBlockIds) > 0 {\n\t\tfor _, subBlockId := range block.SubBlockIds {\n\t\t\terr := DeleteBlock(ctx, subBlockId, recursive)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"error deleting subblock %s: %w\", subBlockId, err)\n\t\t\t}\n\t\t}\n\t}\n\tparentBlockCount, err := deleteBlockObj(ctx, blockId)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error deleting block: %w\", err)\n\t}\n\tlog.Printf(\"DeleteBlock: parentBlockCount: %d\", parentBlockCount)\n\tparentORef := waveobj.ParseORefNoErr(block.ParentORef)","sourceCodeStart":142,"sourceCodeEnd":178,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/pkg/wcore/block.go#L142-L178","documentation":"DeleteBlock first fetches the Block by id. If the underlying DB read itself fails (storage error, not merely a nil row) it wraps the failure as \"error getting block: %w\" and aborts the delete. This distinguishes database-level failures from the benign block==nil case, which returns nil (already deleted).","triggerScenarios":"Calling DeleteBlock / DeleteTab / DeleteBlockCommand when the DBGet on the block store returns a non-nil error — corrupt store, transaction/IO failure, or an underlying waveobj update-layer error while decoding the object.","commonSituations":"Corrupt or locked local waveworks DB after a crash; concurrent process writing the DB; deserialization issue with a malformed block record.","solutions":["Inspect the wrapped cause (%w) to identify the underlying DB/IO failure.","Retry the delete after the store is healthy; DeleteBlock is idempotent for missing blocks.","Repair/rebuild the waveworks store if the block record is corrupt.","Check for concurrent writers/lock contention on the DB file."],"exampleFix":"// before\nerr := wclient.DeleteBlock(ctx, blockId, false) // opaque failure\n// after\nif err := wclient.DeleteBlock(ctx, blockId, false); err != nil {\n    log.Printf(\"delete failed, cause: %v\", errors.Unwrap(err))\n}","handlingStrategy":"try-catch","validationCode":"if blockId == \"\" { return errors.New(\"blockId required\") }","typeGuard":null,"tryCatchPattern":"if err := wcore.DeleteBlock(ctx, blockId, false); err != nil {\n    var cause error\n    errors.As(err, &cause)\n    log.Printf(\"DeleteBlock %s failed: %v (cause: %v)\", blockId, err, cause)\n    return err\n}","preventionTips":["Log errors.Unwrap chains to distinguish storage failures from missing blocks.","Keep the waveworks DB healthy (clean shutdowns, backup/repair tooling).","Remember nil block == already deleted; only treat DB errors as failures."],"tags":["wave-terminal","block-deletion","database-read","wrapped-error"],"backgroundTag":"database-read-failed","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}