{"record":{"id":"5c94aa3c93ef239b","repo":"gastownhall/beads","slug":"failed-to-open-jsonl-w","errorCode":null,"errorMessage":"failed to open JSONL: %w","messagePattern":"failed to open JSONL: %w","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/bd/doctor/migration_validation.go","lineNumber":387,"sourceCode":"\n// findJSONLFile locates the JSONL file in a .beads directory.\n// Temporary: will be removed with Phase 2c (doctor JSONL cleanup).\nfunc findJSONLFile(beadsDir string) string {\n\tfor _, name := range []string{\"issues.jsonl\", \"beads.jsonl\"} {\n\t\tp := filepath.Join(beadsDir, name)\n\t\tif _, err := os.Stat(p); err == nil {\n\t\t\treturn p\n\t\t}\n\t}\n\treturn \"\"\n}\n\n// validateJSONLForMigration validates a JSONL file for migration readiness.\n// Returns: count of valid issues, count of malformed lines, set of valid IDs, and error if blocking.\nfunc validateJSONLForMigration(jsonlPath string) (int, int, map[string]bool, error) {\n\tfile, err := os.Open(jsonlPath) //nolint:gosec\n\tif err != nil {\n\t\treturn 0, 0, nil, fmt.Errorf(\"failed to open JSONL: %w\", err)\n\t}\n\tdefer file.Close()\n\n\tids := make(map[string]bool)\n\tvar malformed int\n\tvar parseErrors []string\n\n\tscanner := bufio.NewScanner(file)\n\tscanner.Buffer(make([]byte, 0, 1024), 2*1024*1024) // 2MB buffer for large lines\n\tlineNo := 0\n\n\tfor scanner.Scan() {\n\t\tlineNo++\n\t\tline := scanner.Bytes()\n\t\tif len(line) == 0 {\n\t\t\tcontinue\n\t\t}\n","sourceCodeStart":369,"sourceCodeEnd":405,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/cmd/bd/doctor/migration_validation.go#L369-L405","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Generate the export first: run bd sync (or bd export) so .beads/issues.jsonl exists.","Verify the path: ls -la <path>/.beads/issues.jsonl and correct --path if wrong.","Fix file permissions (chmod u+r) if the file exists but is unreadable.","Ensure the path is a file, not a directory, if it was replaced by something odd."],"exampleFix":"// before\n$ bd doctor migrate-check\nError: failed to open JSONL: open .beads/issues.jsonl: no such file or directory\n// after\n$ bd sync\n$ bd doctor migrate-check\n✓ JSONL valid","handlingStrategy":"validation","validationCode":"info, err := os.Stat(jsonlPath)\nif err != nil {\n    return fmt.Errorf(\"JSONL not ready for migration check: %w (run bd sync first)\", err)\n}\nif info.IsDir() {\n    return fmt.Errorf(\"%s is a directory, expected a file\", jsonlPath)\n}","typeGuard":null,"tryCatchPattern":"valid, malformed, ids, err := validateJSONLForMigration(jsonlPath)\nif err != nil {\n    var perr *fs.PathError\n    if errors.As(err, &perr) && os.IsNotExist(perr) {\n        return fmt.Errorf(\"run 'bd sync' to generate %s before migration\", jsonlPath)\n    }\n    return err\n}","preventionTips":["Always run bd sync (or bd export) before migration readiness checks.","Confirm .beads/issues.jsonl exists at the exact path passed to doctor.","Keep read permissions on .beads for the user running bd.","Verify --path points at the repo root, not a subdirectory."],"tags":["jsonl","filesystem","migration"],"backgroundTag":"jsonl-file-missing","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}