wavetermdev/waveterm · error
parent block not found: %q
Error message
parent block not found: %q
What it means
Inside createSubBlockObj's transaction, the parent block is looked up by ID via wstore.DBGet; if no Block with that OID exists, creation aborts. A sub-block cannot be attached to a nonexistent parent.
Source
Thrown at pkg/wcore/block.go:45
}
if blockDef.Meta == nil || blockDef.Meta.GetString(waveobj.MetaKey_View, "") == "" {
return nil, fmt.Errorf("no view provided for new block")
}
blockData, err := createSubBlockObj(ctx, blockId, blockDef)
if err != nil {
return nil, fmt.Errorf("error creating sub block: %w", err)
}
blockView := blockDef.Meta.GetString(waveobj.MetaKey_View, "")
blockController := blockDef.Meta.GetString(waveobj.MetaKey_Controller, "")
go recordBlockCreationTelemetry(blockView, blockController, true)
return blockData, nil
}
func createSubBlockObj(ctx context.Context, parentBlockId string, blockDef *waveobj.BlockDef) (*waveobj.Block, error) {
return wstore.WithTxRtn(ctx, func(tx *wstore.TxWrap) (*waveobj.Block, error) {
parentBlock, _ := wstore.DBGet[*waveobj.Block](tx.Context(), parentBlockId)
if parentBlock == nil {
return nil, fmt.Errorf("parent block not found: %q", parentBlockId)
}
blockId := uuid.NewString()
blockData := &waveobj.Block{
OID: blockId,
ParentORef: waveobj.MakeORef(waveobj.OType_Block, parentBlockId).String(),
RuntimeOpts: nil,
Meta: blockDef.Meta,
}
wstore.DBInsert(tx.Context(), blockData)
parentBlock.SubBlockIds = append(parentBlock.SubBlockIds, blockId)
wstore.DBUpdate(tx.Context(), parentBlock)
return blockData, nil
})
}
func CreateBlock(ctx context.Context, tabId string, blockDef *waveobj.BlockDef, rtOpts *waveobj.RuntimeOpts) (rtnBlock *waveobj.Block, rtnErr error) {
return CreateBlockWithTelemetry(ctx, tabId, blockDef, rtOpts, true)
}View on GitHub (pinned to a4447c1563)
Solutions
- Fetch the current block list and use a live parent blockId
- Re-query the block before creating a sub-block instead of reusing a cached ID
- Handle the deletion case in UI code by refreshing block state before issuing the create
Example fix
// before
block, err := wcore.CreateSubBlock(ctx, staleBlockId, blockDef)
// after
parent, _ := wstore.DBGet[*waveobj.Block](ctx, parentBlockId)
if parent != nil {
block, err := wcore.CreateSubBlock(ctx, parentBlockId, blockDef)
} Defensive patterns
Strategy: validation
Validate before calling
parent, _ := wstore.DBGet[*waveobj.Block](ctx, parentBlockId)
if parent == nil {
return fmt.Errorf("cannot create sub-block: parent %s no longer exists", parentBlockId)
} Try / catch
block, err := wcore.CreateSubBlock(ctx, parentBlockId, blockDef)
if err != nil && strings.Contains(err.Error(), "parent block not found") {
// refresh block list / pick a valid parent
} Prevention
- Re-fetch block IDs from the store instead of caching them
- Handle block-closed events before issuing sub-block creation
- Use current UI state (not stale layout data) for parent IDs
When it happens
Trigger: createSubBlockObj / CreateSubBlock called with a parentBlockId that does not exist in the Wave object store (already closed/deleted, or never existed).
Common situations: Client cached a stale block ID after the block was closed; race where the parent block was deleted between UI action and RPC; mistyped blockId in scripts.
Understand the failure class
Background: "Not found" and "does not exist" errors: why "Task not found", "No such folder", and "Can't find" fire when a lookup comes back empty — this error's family across 14 libraries.
Related errors
- error getting block: %w
- error getting tab blocks: %w
- error creating sub block: %w
- error creating block: %w
- error getting client: %v
AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01).
Data as JSON: /api/errors/5f752bd51199be83.
Report an issue: GitHub.