gastownhall/beads · error

failed to open JSONL: %w

Error message

failed to open JSONL: %w

What it means

validateJSONLForMigration opens the .beads/issues.jsonl export to validate it before a migration. If os.Open fails, the error is wrapped as 'failed to open JSONL' and validation aborts with zero counts. Usually this simply means the JSONL file does not exist at the expected path.

Source

Thrown at cmd/bd/doctor/migration_validation.go:387

// findJSONLFile locates the JSONL file in a .beads directory.
// Temporary: will be removed with Phase 2c (doctor JSONL cleanup).
func findJSONLFile(beadsDir string) string {
	for _, name := range []string{"issues.jsonl", "beads.jsonl"} {
		p := filepath.Join(beadsDir, name)
		if _, err := os.Stat(p); err == nil {
			return p
		}
	}
	return ""
}

// validateJSONLForMigration validates a JSONL file for migration readiness.
// Returns: count of valid issues, count of malformed lines, set of valid IDs, and error if blocking.
func validateJSONLForMigration(jsonlPath string) (int, int, map[string]bool, error) {
	file, err := os.Open(jsonlPath) //nolint:gosec
	if err != nil {
		return 0, 0, nil, fmt.Errorf("failed to open JSONL: %w", err)
	}
	defer file.Close()

	ids := make(map[string]bool)
	var malformed int
	var parseErrors []string

	scanner := bufio.NewScanner(file)
	scanner.Buffer(make([]byte, 0, 1024), 2*1024*1024) // 2MB buffer for large lines
	lineNo := 0

	for scanner.Scan() {
		lineNo++
		line := scanner.Bytes()
		if len(line) == 0 {
			continue
		}

View on GitHub (pinned to 71377f2769)

Solutions

  1. Generate the export first: run bd sync (or bd export) so .beads/issues.jsonl exists.
  2. Verify the path: ls -la <path>/.beads/issues.jsonl and correct --path if wrong.
  3. Fix file permissions (chmod u+r) if the file exists but is unreadable.
  4. Ensure the path is a file, not a directory, if it was replaced by something odd.

Example fix

// before
$ bd doctor migrate-check
Error: failed to open JSONL: open .beads/issues.jsonl: no such file or directory
// after
$ bd sync
$ bd doctor migrate-check
✓ JSONL valid
Defensive patterns

Strategy: validation

Validate before calling

info, err := os.Stat(jsonlPath)
if err != nil {
    return fmt.Errorf("JSONL not ready for migration check: %w (run bd sync first)", err)
}
if info.IsDir() {
    return fmt.Errorf("%s is a directory, expected a file", jsonlPath)
}

Try / catch

valid, malformed, ids, err := validateJSONLForMigration(jsonlPath)
if err != nil {
    var perr *fs.PathError
    if errors.As(err, &perr) && os.IsNotExist(perr) {
        return fmt.Errorf("run 'bd sync' to generate %s before migration", jsonlPath)
    }
    return err
}

Prevention

When it happens

Trigger: os.Open(jsonlPath) returns an error — file missing (ENOENT), permission denied, or the path is a directory. Raised when CheckMigrationReadiness or CheckMigrationCompletion calls this validator.

Common situations: Running migration checks before ever running bd sync (no export yet); typo'd or wrong --path to the beads dir; JSONL deleted or never committed; permissions changed by another tool.

Related errors


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