gastownhall/beads · error
missing source path for porcelain rename/copy record %q
Error message
missing source path for porcelain rename/copy record %q
What it means
In porcelain -z output, rename (R) and copy (C) records are followed by a second NUL-separated field: the original (source) path. bd consumes that next record to include both endpoints in the fingerprint; this error means the expected source path was absent or empty, so the status stream is truncated or malformed.
Source
Thrown at cmd/bd/worktree_cmd.go:1137
}
func fingerprintWorktreeStatusPaths(worktreePath, status string) (string, error) {
records := strings.Split(status, "\x00")
pathSet := make(map[string]struct{})
for index := 0; index < len(records); index++ {
record := records[index]
if record == "" {
continue
}
if len(record) < 4 || record[2] != ' ' {
return "", fmt.Errorf("unexpected porcelain status record %q", record)
}
code := record[:2]
pathSet[record[3:]] = struct{}{}
if strings.ContainsAny(code, "RC") {
index++
if index >= len(records) || records[index] == "" {
return "", fmt.Errorf("missing source path for porcelain rename/copy record %q", record)
}
pathSet[records[index]] = struct{}{}
}
}
paths := make([]string, 0, len(pathSet))
for path := range pathSet {
paths = append(paths, path)
}
sort.Strings(paths)
hasher := sha256.New()
for _, gitPath := range paths {
cleanPath := filepath.Clean(filepath.FromSlash(gitPath))
if cleanPath == "." ||
filepath.IsAbs(cleanPath) ||
cleanPath == ".." ||
strings.HasPrefix(cleanPath, ".."+string(filepath.Separator)) {View on GitHub (pinned to 71377f2769)
Solutions
- Regenerate status directly from git to confirm output is complete: `git -C <worktree> status --porcelain=v1 -z --untracked-files=all --ignored=matching`
- Check for R/C entries (`git status --porcelain=v1`) and verify each has a preceding `->` source in non-z form; upgrade git if output looks truncated
- If this comes from a test/mock, fix the fixture to include the NUL-separated source path after each R/C record
Example fix
// before (bad fixture) "R new.txt\x00" // after "R new.txt\x00old.txt\x00"
Defensive patterns
Strategy: validation
Validate before calling
records := strings.Split(status, "\x00")
for i, r := range records {
if len(r) > 2 && strings.ContainsAny(r[:2], "RC") {
if i+1 >= len(records) || records[i+1] == "" {
return fmt.Errorf("fixture/truncated output: R/C record %q lacks source path", r)
}
}
} Prevention
- When mocking porcelain output in tests, always append the NUL-separated source path after R/C records
- Never pass hand-trimmed status text into worktree tooling
- Verify rename serialization with real `git status -z` output
When it happens
Trigger: fingerprintWorktreeStatusPaths sees an R/C status code but the next NUL-separated record is empty or missing — truncated `git status` output or a caller passing a hand-built/partial status string.
Common situations: Renamed files in the index combined with output truncation; testing/mocking code that fabricates porcelain records without the rename source; a git build emitting non-standard rename serialization.
Related errors
- unexpected porcelain status record %q
- unexpected git rev-parse output
- dolt version output is unparseable
- parsing batch input: %w
- line %d: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/b90b668e3f61093d.
Report an issue: GitHub.