{"record":{"id":"da31acaaa10b85ec","repo":"wavetermdev/waveterm","slug":"bad-block-parent-oref-v","errorCode":null,"errorMessage":"bad block parent oref: %v","messagePattern":"bad block parent oref: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/wstore/wstore_dbops.go","lineNumber":378,"sourceCode":"\t\treturn nil\n\t})\n}\n\nfunc DBFindTabForBlockId(ctx context.Context, blockId string) (string, error) {\n\treturn WithTxRtn(ctx, func(tx *TxWrap) (string, error) {\n\t\titerNum := 1\n\t\tfor {\n\t\t\tif iterNum > 5 {\n\t\t\t\treturn \"\", fmt.Errorf(\"too many iterations looking for tab in block parents\")\n\t\t\t}\n\t\t\tquery := `\n\t\t\tSELECT json_extract(b.data, '$.parentoref') AS parentoref\n\t\t\tFROM db_block b\n\t\t\tWHERE b.oid = ?;`\n\t\t\tparentORef := tx.GetString(query, blockId)\n\t\t\toref, err := waveobj.ParseORef(parentORef)\n\t\t\tif err != nil {\n\t\t\t\treturn \"\", fmt.Errorf(\"bad block parent oref: %v\", err)\n\t\t\t}\n\t\t\tif oref.OType == \"tab\" {\n\t\t\t\treturn oref.OID, nil\n\t\t\t}\n\t\t\tif oref.OType == \"block\" {\n\t\t\t\tblockId = oref.OID\n\t\t\t\titerNum++\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\treturn \"\", fmt.Errorf(\"bad parent oref type: %v\", oref.OType)\n\t\t}\n\t})\n}\n\nfunc DBFindWorkspaceForTabId(ctx context.Context, tabId string) (string, error) {\n\treturn WithTxRtn(ctx, func(tx *TxWrap) (string, error) {\n\t\tquery := `\n\t\t\tWITH variable(value) AS (","sourceCodeStart":360,"sourceCodeEnd":396,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/pkg/wstore/wstore_dbops.go#L360-L396","documentation":"While walking a block's parent chain, DBFindTabForBlockId parses each parentoref string into an ORef. If the stored parentoref is empty, malformed, or not a valid 'type:id' reference, ParseORef fails and the error is wrapped with this message.","triggerScenarios":"A db_block row whose JSON $.parentoref is empty string, truncated, or contains an invalid reference format passed to waveobj.ParseORef during DBFindTabForBlockId.","commonSituations":"Database rows written by older/buggy versions with missing parent fields; manual DB edits; objects copied between databases losing their parent linkage.","solutions":["Fix or delete the corrupt db_block row so parentoref is a valid 'tab:...' or 'block:...' ORef","Re-establish the parent relationship by moving the block into a tab via the layout API","Guard callers: check block has a parent before resolving, and log the raw parentoref value for diagnosis"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"raw := getBlockParentORef(blockId) // your own read\nif _, err := waveobj.ParseORef(raw); err != nil { /* repair before traversal */ }","typeGuard":null,"tryCatchPattern":"tabId, err := wstore.DBFindTabForBlockId(ctx, blockId)\nif err != nil && strings.Contains(err.Error(), \"bad block parent oref\") {\n\t// repair or re-parent the block, then retry\n}","preventionTips":["Only set parentoref via the layout APIs, never raw strings","Validate ORefs with ParseORef before persisting","Backup/migrate DB rows when upgrading versions"],"tags":["sqlite","oref","data-corruption"],"backgroundTag":"invalid-oref-format","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}