{"record":{"id":"9607711728b314eb","repo":"wavetermdev/waveterm","slug":"too-many-iterations-looking-for-tab-in-block-paren","errorCode":null,"errorMessage":"too many iterations looking for tab in block parents","messagePattern":"too many iterations looking for tab in block parents","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/wstore/wstore_dbops.go","lineNumber":369,"sourceCode":"\tif err != nil {\n\t\treturn err\n\t}\n\treturn WithTx(ctx, func(tx *TxWrap) error {\n\t\ttable := waveObjTableName(val)\n\t\twaveobj.SetVersion(val, 1)\n\t\tquery := fmt.Sprintf(\"INSERT INTO %s (oid, version, data) VALUES (?, ?, ?)\", table)\n\t\ttx.Exec(query, oid, 1, jsonData)\n\t\twaveobj.ContextAddUpdate(ctx, waveobj.WaveObjUpdate{UpdateType: waveobj.UpdateType_Update, OType: val.GetOType(), OID: oid, Obj: val})\n\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}","sourceCodeStart":351,"sourceCodeEnd":387,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/pkg/wstore/wstore_dbops.go#L351-L387","documentation":"DBFindTabForBlockId walks the parent chain of blocks (block -> parent oref -> ...) up to 5 hops to find the enclosing tab. If it has not reached a tab after 5 iterations it gives up with this error, protecting against cycles or unexpectedly deep block nesting in the layout tree.","triggerScenarios":"Passing a blockId whose parent chain is longer than 5 block levels, a cyclic parentoref layout, or a corrupted block row whose parent points back into the same block tree indefinitely.","commonSituations":"Deeply nested split/pane layouts created programmatically; corrupted waveai/state DB rows with self-referential parent orefs; calling the function with a root-level block whose chain never terminates in a tab.","solutions":["Inspect the block's parent chain (db_block.parentoref values) for cycles or excessive depth and repair the layout","Re-create or flatten the offending nested layout so the tab is within 5 levels","Verify blockId is valid and the chain terminates at a tab, not another container type"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"tabId, err := wstore.DBFindTabForBlockId(ctx, blockId)\nif err != nil {\n\tif strings.Contains(err.Error(), \"too many iterations\") {\n\t\t// fall back to workspace-level lookup or rebuild layout\n\t}\n\treturn err\n}","preventionTips":["Avoid nesting blocks more than a few levels deep","Watch for cyclic parentoref assignments when building custom layouts","Log the parent chain when traversal fails to spot corruption"],"tags":["sqlite","layout","traversal-limit"],"backgroundTag":"parent-chain-cycle","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}