gastownhall/beads · error
unknown source kind %q for %s
Error message
unknown source kind %q for %s
What it means
The SourceKind on a hook migration write op is a closed enum (template, hook file, old, backup). If renderMigratedHookContent sees any other value, it fails fast rather than guessing how to build content — this indicates an internal inconsistency between the planner and the renderer.
Source
Thrown at cmd/bd/migrate_hooks_apply.go:320
}
return prepared, nil
}
func renderMigratedHookContent(op hookMigrationWriteOp) ([]byte, error) {
var baseContent string
switch op.SourceKind {
case hookMigrationWriteFromTemplate:
baseContent = ""
case hookMigrationWriteFromHookFile, hookMigrationWriteFromOld, hookMigrationWriteFromBackup:
content, err := os.ReadFile(op.SourcePath) // #nosec G304 -- source paths come from migration planner + known sidecar suffixes
if err != nil {
return nil, fmt.Errorf("reading source content for %s from %s: %w", op.HookName, op.SourcePath, err)
}
baseContent = string(content)
default:
return nil, fmt.Errorf("unknown source kind %q for %s", op.SourceKind, op.HookName)
}
baseContent = strings.ReplaceAll(baseContent, "\r\n", "\n")
baseContent = ensureHookShebang(baseContent)
content := injectHookSection(baseContent, generateHookSection(op.HookName))
content = strings.ReplaceAll(content, "\r\n", "\n")
if !strings.HasSuffix(content, "\n") {
content += "\n"
}
return []byte(content), nil
}
func ensureHookShebang(content string) string {
if strings.HasPrefix(content, "#!") {
return content
}View on GitHub (pinned to 71377f2769)
Solutions
- Upgrade bd so planner and renderer share the same source-kind set
- Re-generate the migration plan with the current binary instead of reusing a stale one
- Report a bug if it reproduces on the latest version — this is an internal invariant violation
- Add a renderer case for the new SourceKind if you are developing bd and introduced a new kind
Defensive patterns
Strategy: type-guard
Validate before calling
const knownKinds = new Set(['template','hook_file','old','backup']);
if (!knownKinds.has(op.SourceKind)) throw new Error('unknown SourceKind: '+op.SourceKind); Type guard
func validSourceKind(k hookMigrationSourceKind) bool { switch k { case hookMigrationWriteFromTemplate, hookMigrationWriteFromHookFile, hookMigrationWriteFromOld, hookMigrationWriteFromBackup: return true }; return false } Try / catch
if err := apply(...); err != nil && strings.Contains(err.Error(), "unknown source kind") {
// regenerate the plan with the current binary and retry
} Prevention
- Regenerate plans with the same binary version that applies them
- Never hand-edit or cache migration plans across upgrades
- If developing bd, add a renderer case whenever a new SourceKind is introduced
When it happens
Trigger: A hookMigrationRetireOp/write op carries a SourceKind outside the four known constants, produced by newer planner code or a corrupted plan structure passed to prepareHookMigrationWrites.
Common situations: Version mismatch where planner and apply code disagree on the enum; hand-built or serialized plans modified externally; a code bug adding a new source kind without a renderer case.
Related errors
- %s has unsupported migration state %q
- %s does not require migration
- hook migration blocked by %d issue(s): %s
- reading source content for %s from %s: %w
- ExternalDoltConfig: TLSCert set without TLSKey
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/b20f88ac288e9adc.
Report an issue: GitHub.