gastownhall/beads · error

scan inbound dependency: %w

Error message

scan inbound dependency: %w

What it means

DeleteResolvedSetInTx aborts when scanning a row of the inbound-dependency result set fails — the issue_id column could not be read into a string. This indicates unexpected column types or a NULL in a column the query expects to be a non-NULL string, wrapped with the driver's scan error.

Source

Thrown at internal/storage/issueops/delete.go:261

		}
		batch := set.All[i:end]
		batchInClause, batchArgs := buildSQLInClause(batch)

		for _, depTable := range []string{"dependencies", "wisp_dependencies"} {
			rows, err := tx.QueryContext(ctx,
				fmt.Sprintf(`SELECT issue_id FROM %s WHERE %s`, depTable, depTargetIn("", batchInClause)),
				batchArgs...)
			if err != nil {
				if optionalBlockedTable(depTable) && isTableNotExistError(err) {
					continue
				}
				return nil, fmt.Errorf("count inbound dependencies from %s: %w", depTable, err)
			}
			for rows.Next() {
				var issID string
				if err := rows.Scan(&issID); err != nil {
					_ = rows.Close()
					return nil, fmt.Errorf("scan inbound dependency: %w", err)
				}
				if !deletedSet[issID] {
					depsCount++
				}
			}
			_ = rows.Close()
			if err := rows.Err(); err != nil {
				return nil, fmt.Errorf("iterate inbound dependencies from %s: %w", depTable, err)
			}
		}
	}

	result.DependenciesCount = depsCount
	result.LabelsCount = labelsCount
	result.EventsCount = eventsCount
	result.DeletedCount = len(set.RegularIDs) + len(set.WispIDs)

	if dryRun {

View on GitHub (pinned to 71377f2769)

Solutions

  1. Find the row(s) with NULL/non-string issue_id in the named dependency table and repair or delete them.
  2. Run a schema/data integrity check (bd doctor) on the database.
  3. Restore from backup if rows are corrupted.
  4. Ensure imports/conversions always populate issue_id NOT NULL.

Example fix

// before
// NULL issue_id row corrupts delete
// after
UPDATE dependencies SET issue_id = '<recovered-id>' WHERE issue_id IS NULL;
-- or delete the orphan edge:
DELETE FROM dependencies WHERE issue_id IS NULL;
Defensive patterns

Strategy: validation

Validate before calling

// detect corrupt edges before deleting
rows, err := db.QueryContext(ctx,
    `SELECT COUNT(*) FROM dependencies WHERE issue_id IS NULL OR target_id IS NULL`)
if err != nil {
    return err
}
var bad int
_ = rows.Scan(&bad)
if bad > 0 {
    return fmt.Errorf("%d dependency rows have NULL ids; repair before delete", bad)
}

Try / catch

err := batchDelete(ctx, tx, ids)
if err != nil && strings.Contains(err.Error(), "scan inbound dependency") {
    return fmt.Errorf("corrupt dependency row (NULL/non-string id); run integrity repair: %w", err)
}

Prevention

When it happens

Trigger: Calling DeleteIssuesInTx/DeleteInTx when a dependency table's issue_id/target column contains NULL or a non-string value, typically from schema drift, manual edits, or a driver returning different column types.

Common situations: Hand-edited or externally imported databases with NULL issue_id values; a custom driver that returns []byte vs string incompatibly; corrupted rows after a crash.

Related errors


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