gastownhall/beads · error

journal: marshal dep for %s: %w

Error message

journal: marshal dep for %s: %w

What it means

insertEventRow marshals the EventDep payload to JSON for dependency journal rows; failure is wrapped as 'journal: marshal dep for %s'. EventDep is a small fixed struct so failures indicate corrupted dependency data or incompatible field types.

Source

Thrown at internal/storage/issueops/journal.go:433

// plumbings funnel through, so the seq mechanism cannot drift between them. A
// nil issue is stored as SQL NULL (deletes); a nil dep is stored as SQL NULL
// (non-dependency ops). ts is the insert time, stamped inside the committing
// transaction. actor is stored as-is — "" for the genuinely unattributable
// paths — in the NOT NULL DEFAULT ” actor column.
func insertEventRow(ctx context.Context, tx DBTX, op EventOp, issueID string, issue *types.Issue, dep *EventDep, comment *EventComment, actor string) error {
	var issueJSON any
	if issue != nil {
		b, err := json.Marshal(issue)
		if err != nil {
			return fmt.Errorf("journal: marshal issue %s: %w", issueID, err)
		}
		issueJSON = string(b)
	}
	var depJSON any
	if dep != nil {
		b, err := json.Marshal(dep)
		if err != nil {
			return fmt.Errorf("journal: marshal dep for %s: %w", issueID, err)
		}
		depJSON = string(b)
	}
	var commentJSON any
	if comment != nil {
		b, err := json.Marshal(comment)
		if err != nil {
			return fmt.Errorf("journal: marshal comment for %s: %w", issueID, err)
		}
		commentJSON = string(b)
	}
	insert := func(seq int64) error {
		_, err := tx.ExecContext(ctx, `
			INSERT INTO bd_events_journal (seq, ts, op, issue_id, actor, issue_json, dep_json, comment_json)
			VALUES (?, ?, ?, ?, ?, ?, ?, ?)
		`, seq, time.Now().UTC(), string(op), issueID, actor, issueJSON, depJSON, commentJSON)
		return err
	}

View on GitHub (pinned to 71377f2769)

Solutions

  1. Inspect the wrapped error for the offending field
  2. Construct EventDep only via the library's dependency APIs
  3. Ensure dependency payloads contain only plain strings/bools
  4. Report upstream if standard API usage triggers this

Example fix

// before
dep := &ops.EventDep{IssueID: id, Target: strings.Repeat("\x00", 10)}
ops.RecordDepEventInTx(ctx, tx, op, id, dep)
// after
dep := &ops.EventDep{IssueID: id, Target: targetID} // use valid IDs from the store
ops.RecordDepEventInTx(ctx, tx, op, id, dep)
Defensive patterns

Strategy: try-catch

Validate before calling

if _, err := json.Marshal(dep); err != nil {
    return fmt.Errorf("dep payload invalid: %w", err)
}

Try / catch

if err := ops.RecordDepEventInTx(ctx, tx, op, id, dep); err != nil {
    if strings.Contains(err.Error(), "marshal dep") { return fmt.Errorf("bad dep payload: %w", err) }
    return err
}

Prevention

When it happens

Trigger: RecordDepEventInTx / RecordEventInTx with a *EventDep containing invalid data (nil map edge cases after custom construction, wrong types from a hand-built event).

Common situations: Custom tooling constructing EventDep directly with non-standard values; merge tooling that pasted mismatched struct versions.

Related errors


AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30). Data as JSON: /api/errors/b6bd05024ccf9a21. Report an issue: GitHub.