gastownhall/beads · error
failed to parse issue from JSONL: %w
Error message
failed to parse issue from JSONL: %w
What it means
parseJSONLFile reads a beads JSONL export line by line. After skipping schema headers and memory records, each remaining line is unmarshaled into types.Issue; if the JSON does not decode into a valid Issue struct (malformed JSON, wrong types for fields, truncated line), the whole parse aborts with this wrapped error.
Source
Thrown at cmd/bd/import_shared.go:1041
// Check if this is a memory record
if rawType, ok := peek["_type"]; ok {
var typeStr string
if err := json.Unmarshal(rawType, &typeStr); err == nil && typeStr == "memory" {
var mem memoryRecord
if err := json.Unmarshal([]byte(line), &mem); err != nil {
return nil, nil, fmt.Errorf("failed to parse memory record: %w", err)
}
if mem.Key != "" && mem.Value != "" {
configEntries[kvPrefix+memoryPrefix+mem.Key] = mem.Value
}
continue
}
}
// Regular issue record
var issue types.Issue
if err := json.Unmarshal([]byte(line), &issue); err != nil {
return nil, nil, fmt.Errorf("failed to parse issue from JSONL: %w", err)
}
// Skip tombstone entries: these are deleted issues exported by older
// versions (pre-v0.50) with status "tombstone" and deleted_at set.
// They are not valid for re-import since "tombstone" is not a real status.
if issue.Status == "tombstone" {
continue
}
applyImportWispPlane(peek, &issue)
issue.SetDefaults()
issues = append(issues, &issue)
}
if err := scanner.Err(); err != nil {
return nil, nil, fmt.Errorf("failed to scan JSONL: %w", err)
}
return issues, configEntries, nilView on GitHub (pinned to 71377f2769)
Solutions
- Open the file and run each line through `jq -e .` (or `python -m json.tool`) to find the malformed line named in the wrapped %w error
- Fix or delete the corrupt line (or re-resolve the git merge conflict), keeping one valid JSON object per line
- If the file came from `bd export`, regenerate it with the same bd version instead of hand-editing
- Check for version skew: re-export with the current `bd` binary rather than importing an old-format file
Example fix
// before (corrupt line in .beads/issues.jsonl)
{"id":"bd-1","title":"fix" "priority":1
// after (valid single-line JSON object)
{"id":"bd-1","title":"fix","priority":1} Defensive patterns
Strategy: validation
Validate before calling
// Validate the JSONL before import: one JSON object per line
for i, line := range strings.Split(string(data), "\n") {
line = strings.TrimSpace(line)
if line == "" { continue }
var probe map[string]any
if err := json.Unmarshal([]byte(line), &probe); err != nil {
return fmt.Errorf("line %d is not valid JSON: %w", i+1, err)
}
} Type guard
func isHeaderRecord(line string) bool {
var peek map[string]json.RawMessage
if json.Unmarshal([]byte(line), &peek) != nil { return false }
_, ok := peek["_schema"]
return ok
} Try / catch
if _, _, err := parseJSONLFile(path); err != nil {
var parseErr *json.UnmarshalTypeError
if errors.As(err, &parseErr) {
log.Fatalf("malformed issue record (field %s): %v", parseErr.Field, err)
}
return err
} Prevention
- Never hand-edit issues.jsonl; regenerate with `bd export`
- Resolve git merge conflicts in .beads/ files fully before running bd
- Keep one JSON object per line; validate with jq after any external tooling touches the file
- Use the same (current) bd version for export and import to avoid schema skew
When it happens
Trigger: Calling `bd init --from-jsonl`, `bd bootstrap`, or the auto-import path (maybeAutoImportJSONL / importFromLocalJSONLWithOpts) on a JSONL file where a line that is not a _schema header and not a _type:"memory" record fails json.Unmarshal into types.Issue — e.g. hand-edited lines, corrupted merges, or type mismatches (a string where a timestamp is expected).
Common situations: Git merge conflicts left half-resolved in .beads/issues.jsonl; an external script appended non-beads JSON to the export; a partial/truncated file written during a crash; an export from an incompatible bd version with shifted field types.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- failed to read JSONL file %s: %w
- failed to parse JSONL line: %w
- failed to scan JSONL: %w
- --from-jsonl specified but %s does not exist
- failed to import from JSONL: %v
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/eda810bba39c2d8a.
Report an issue: GitHub.