gastownhall/beads · error
applyGraph: node %q: %w
Error message
applyGraph: node %q: %w
What it means
Wraps any error from the per-node create call during applyGraph pass 1 (inserting each node's issue), annotated with the node's key. Causes are the same as ordinary create failures: validation, prefix mismatch, dependency insert failures, storage errors. IDs minted for previously created nodes are tracked in keyToID, but the apply aborts on the first node failure.
Source
Thrown at internal/storage/domain/issue.go:1138
// callers cannot route wisp-flagged issues into the durable table.
if nodeWisp := node.Issue.Ephemeral || node.Issue.NoHistory; nodeWisp != useWisp {
return GraphApplyResult{}, fmt.Errorf("applyGraph: node %q storage class (ephemeral=%t, no_history=%t) does not match plan routing (wisp=%t)", node.Key, node.Issue.Ephemeral, node.Issue.NoHistory, useWisp)
}
if node.AssignAfterCreate {
pendingAssignees[i] = node.Assignee
node.Issue.Assignee = ""
} else if node.Assignee != "" {
node.Issue.Assignee = node.Assignee
}
params := CreateIssueParams{
Issue: node.Issue,
Labels: node.Labels,
}
r, err := u.create(ctx, params, actor, useWisp)
if err != nil {
return GraphApplyResult{}, fmt.Errorf("applyGraph: node %q: %w", node.Key, err)
}
keyToID[node.Key] = r.Issue.ID
}
// Pass 2 — resolve MetadataRefs now that every node has a minted ID.
// Merges the resolved IDs into the issue's existing metadata JSON and
// writes the result back via Update. Kept inside applyGraph so the CLI
// cannot bypass this step; the proxied caller used to do it post-call.
for _, node := range plan.Nodes {
if len(node.MetadataRefs) == 0 {
continue
}
metaJSON, err := types.MergeMetadataRefs(node.Issue.Metadata, node.MetadataRefs, keyToID)
if err != nil {
return GraphApplyResult{}, fmt.Errorf("applyGraph: node %q: %w", node.Key, err)
}
updates := map[string]any{"metadata": metaJSON}
if err := u.issueRepo.Update(ctx, keyToID[node.Key], updates, actor, IssueTableOpts{UseWispsTable: useWisp}); err != nil {View on GitHub (pinned to 71377f2769)
Solutions
- Read the node key and the wrapped inner error to pinpoint the failing issue payload
- Fix the offending node's issue data (title, IDs, flags) and re-apply the plan
- Make nodes idempotent/skippable if they already exist before re-running apply
- Check storage connectivity/constraints if the wrapped error is driver-level
Example fix
// before: node issue missing required title
plan.Nodes[2].Issue = &types.Issue{}
// after: complete payload before apply
plan.Nodes[2].Issue = &types.Issue{Title: "child task", Status: "open"} Defensive patterns
Strategy: validation
Validate before calling
for _, n := range plan.Nodes {
if n.Issue.Title == "" { return fmt.Errorf("node %q missing title", n.Key) }
for _, dep := range n.Dependencies {
if !planHasKey(plan, dep.DependsOnKey) { return fmt.Errorf("node %q refs unknown key %q", n.Key, dep.DependsOnKey) }
}
}
// also dedupe against existing issues before apply Try / catch
result, err := uc.ApplyGraph(ctx, plan, actor)
if err != nil {
var key string
if _, e := fmt.Sscanf(err.Error(), "applyGraph: node %q", &key); e == nil {
log.Printf("graph apply failed at node %s", key)
// inspect and fix that node, then re-apply idempotently
}
} Prevention
- Validate every node payload (title, flags, deps) before apply
- Ensure all dependency keys reference keys present in the plan
- Check for pre-existing issues with the same IDs to keep apply idempotent
- Regenerate graphs from source instead of hand-editing
When it happens
Trigger: Calling ApplyGraph where u.create fails for a node — invalid issue fields, duplicate ID, bad dependency/label references, or a storage/driver error during insert.
Common situations: Graph files with malformed issue payloads; duplicates of already-existing issues; dependency edges referencing keys that fail to create; transient DB failures mid-apply.
Related errors
- edge %d %s->%s: checking planned blocking cycle: %w
- reading existing dependencies for %s: %w
- no store is open for this workspace
- not found
- db: ChildCounterSQLRepository.NextChildID: parentID must not
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/f0b1623337a3a0de.
Report an issue: GitHub.