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

  1. Fetch the current block list and use a live parent blockId
  2. Re-query the block before creating a sub-block instead of reusing a cached ID
  3. 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

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


AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01). Data as JSON: /api/errors/5f752bd51199be83. Report an issue: GitHub.