gastownhall/beads · error

dependency %s -> %s has invalid type

Error message

dependency %s -> %s has invalid type

What it means

The legacy row's type column does not map to a valid types.DependencyType, so the importer cannot construct a Dependency and aborts. Dependency types are a closed enum (e.g. blocks, parent-child, conditional-blocks) validated by DependencyType.IsValid().

Source

Thrown at internal/migration/legacysqlite/reader.go:926

		return fmt.Errorf("dependency %s -> %s crosses ephemeral storage", id, to)
	}
	key := id + "\x00" + to
	if seenDeps[key] {
		return fmt.Errorf("multiple legacy dependencies for %s -> %s", id, to)
	}
	seenDeps[key] = true
	created, e := parseTime(at)
	if e != nil {
		return e
	}
	if created.IsZero() {
		return fmt.Errorf("dependency created_at is zero for %s -> %s", id, to)
	}
	if (metadata.Valid && metadata.String != "") || (thread.Valid && thread.String != "") {
		return fmt.Errorf("dependency %s -> %s uses unsupported metadata or thread ID", id, to)
	}
	if !types.DependencyType(typ).IsValid() {
		return fmt.Errorf("dependency %s -> %s has invalid type", id, to)
	}
	d := &types.Dependency{IssueID: id, DependsOnID: to, Type: types.DependencyType(typ), CreatedAt: created, CreatedBy: by, Metadata: nullString(metadata), ThreadID: nullString(thread)}
	issue.Dependencies = append(issue.Dependencies, d)
	return nil
}

func loadComments(ctx context.Context, db *sql.Tx, byID map[string]*types.Issue) error {
	comments, err := db.QueryContext(ctx, "SELECT id,issue_id,author,text,CAST(created_at AS TEXT) FROM comments ORDER BY issue_id,created_at,id")
	if err != nil {
		return err
	}
	defer comments.Close()
	type commentIdentity struct {
		issueID, author, text string
		createdAt             time.Time
	}
	seenComments := make(map[commentIdentity]int64)
	for comments.Next() {

View on GitHub (pinned to 71377f2769)

Solutions

  1. Inspect offending rows: SELECT * FROM dependencies WHERE type NOT IN (<valid types>) and fix them to a valid type
  2. Update unknown types to their modern equivalents (e.g. legacy 'related' -> appropriate valid type) in the legacy DB
  3. Remove rows with unrecoverable type values and recreate the dependencies in bd after migration

Example fix

-- before
-- type = 'watch'
UPDATE dependencies SET type = 'blocks' WHERE type = 'watch';
-- after: type is a valid DependencyType
Defensive patterns

Strategy: validation

Validate before calling

const VALID = new Set(['blocks','conditional-blocks','parent-child','related']);
for (const d of legacyDeps) {
  if (!VALID.has(String(d.type)))
    throw new Error(`invalid dependency type '${d.type}' on ${d.issue_id} -> ${d.depends_on_id}`);
}

Type guard

function hasValidType(d, validTypes) {
  return validTypes.some(t => String(d.type) === t);
}

Try / catch

try { migrateLegacySQLite(dbPath) } catch (e) {
  if (e.message.includes('has invalid type')) {
    fixUnknownDepTypes(dbPath); // map legacy names -> valid types
    retry();
  } else throw e;
}

Prevention

When it happens

Trigger: Legacy SQLite dependency rows whose type value is not one of the recognized dependency type strings/ints — e.g. from an even older schema, corrupted data, or hand-edited SQL.

Common situations: Restored or partially-migrated legacy databases; rows inserted by tooling that used free-form type strings; version mismatch where legacy type names were later renamed.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


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