{"record":{"id":"2ee022958576e814","repo":"gastownhall/beads","slug":"removing-already-retired-sidecar-s-w","errorCode":null,"errorMessage":"removing already-retired sidecar %s: %w","messagePattern":"removing already-retired sidecar (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/bd/migrate_hooks_apply.go","lineNumber":405,"sourceCode":"\tif !sourceExists {\n\t\treturn \"\", nil\n\t}\n\n\tdestinationExists, err := pathExists(op.DestinationPath)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"checking sidecar destination %s: %w\", op.DestinationPath, err)\n\t}\n\n\tif destinationExists {\n\t\tequal, err := filesEqual(op.SourcePath, op.DestinationPath)\n\t\tif err != nil {\n\t\t\treturn \"\", fmt.Errorf(\"comparing sidecar %s to %s: %w\", op.SourcePath, op.DestinationPath, err)\n\t\t}\n\t\tif !equal {\n\t\t\treturn \"\", fmt.Errorf(\"artifact collision for %s: %s already exists with different content\", op.SourcePath, op.DestinationPath)\n\t\t}\n\t\tif err := os.Remove(op.SourcePath); err != nil {\n\t\t\treturn \"\", fmt.Errorf(\"removing already-retired sidecar %s: %w\", op.SourcePath, err)\n\t\t}\n\t\treturn op.SourcePath + \" -> \" + op.DestinationPath + \" (destination already existed)\", nil\n\t}\n\n\tif err := os.Rename(op.SourcePath, op.DestinationPath); err != nil {\n\t\treturn \"\", fmt.Errorf(\"retiring sidecar %s -> %s: %w\", op.SourcePath, op.DestinationPath, err)\n\t}\n\n\treturn op.SourcePath + \" -> \" + op.DestinationPath, nil\n}\n\nfunc pathExists(path string) (bool, error) {\n\t_, err := os.Stat(path)\n\tif err == nil {\n\t\treturn true, nil\n\t}\n\tif errors.Is(err, os.ErrNotExist) {\n\t\treturn false, nil","sourceCodeStart":387,"sourceCodeEnd":423,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/cmd/bd/migrate_hooks_apply.go#L387-L423","documentation":"This wraps os.Remove failure when deleting the source sidecar that has already been confirmed identical to an existing destination. The migration verified both files match, but unlinking the redundant source failed. The destination file remains intact; the source is left in place.","triggerScenarios":"During `bd migrate` apply, os.Remove(op.SourcePath) fails — source directory lacks write permission (removing a file requires write on its directory), the file was locked by another process on Windows, or the directory is read-only.","commonSituations":"Source directory mounted read-only; parent directory owned by another user (no +w); Windows AV/indexer holding the file open; immutable attribute set on the file.","solutions":["Check the wrapped error and permissions on the source's parent directory (write permission is what matters).","chmod u+w the parent directory, or remove the immutable flag: chattr -i <file>.","On Windows, close processes holding the file (AV, editors) and retry.","Since destination content is already identical, manually deleting the source and re-running is safe."],"exampleFix":"// before\ndr-xr-xr-x /path/to/dir\n// after\n$ chmod u+w /path/to/dir\n$ bd migrate","handlingStrategy":"validation","validationCode":"fi, err := os.Stat(filepath.Dir(op.SourcePath))\nif err != nil {\n\treturn err\n}\nif fi.Mode()&0o200 == 0 {\n\treturn fmt.Errorf(\"source dir %s not writable; os.Remove will fail\", filepath.Dir(op.SourcePath))\n}","typeGuard":null,"tryCatchPattern":"if _, err := retireHookSidecar(op); err != nil {\n\tvar pe *fs.PathError\n\tif errors.As(err, &pe) {\n\t\treturn fmt.Errorf(\"cannot delete %s (check dir write perms / file locks): %w\", pe.Path, pe.Err)\n\t}\n\treturn err\n}","preventionTips":["Ensure write permission on the directory containing the source sidecar","Clear the immutable flag if set: chattr -i <file>","On Windows, close editors/AV holding the file before migrating"],"tags":["filesystem","permissions","migration","go"],"backgroundTag":"permission-denied","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}