{"record":{"id":"a963d050df774c2e","repo":"gastownhall/beads","slug":"rotating-s-s-w","errorCode":null,"errorMessage":"rotating %s -> %s: %w","messagePattern":"rotating (.+?) -> (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/doltserver/logrotate.go","lineNumber":98,"sourceCode":"func rotateLogIfOversized(primary string, maxBytes int64) (bool, error) {\n\tif maxBytes <= 0 {\n\t\treturn false, nil\n\t}\n\tinfo, err := os.Stat(primary)\n\tif err != nil {\n\t\tif os.IsNotExist(err) {\n\t\t\treturn false, nil\n\t\t}\n\t\treturn false, fmt.Errorf(\"stat %s: %w\", primary, err)\n\t}\n\tif info.Size() <= maxBytes {\n\t\treturn false, nil\n\t}\n\trotated := rotatedLogPath(primary)\n\t// os.Rename overwrites the destination on both Unix and Windows (Go's\n\t// Rename wraps MoveFileEx with MOVEFILE_REPLACE_EXISTING on Windows).\n\tif err := os.Rename(primary, rotated); err != nil {\n\t\treturn false, fmt.Errorf(\"rotating %s -> %s: %w\", primary, rotated, err)\n\t}\n\treturn true, nil\n}\n\n// maybeRotateLog is the convenience wrapper used by Start(). It rotates the\n// dolt-server log if it is oversized and emits a debug message on both\n// rotation and error paths. It never returns an error — rotation is\n// best-effort and must not block server startup.\nfunc maybeRotateLog(beadsDir string) {\n\tprimary := logPath(beadsDir)\n\tmax := maxLogBytes()\n\trotated, err := rotateLogIfOversized(primary, max)\n\tif err != nil {\n\t\tdebug.Logf(\"doltserver: log rotation failed for %s: %v\", primary, err)\n\t\treturn\n\t}\n\tif rotated {\n\t\tdebug.Logf(\"doltserver: rotated %s -> %s (exceeded %d bytes)\", primary, rotatedLogPath(primary), max)","sourceCodeStart":80,"sourceCodeEnd":116,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/doltserver/logrotate.go#L80-L116","documentation":"rotateLogIfOversized wraps os.Rename(primary, rotated) failures as \"rotating %s -> %s: %w\". Rename overwrites the destination on both Unix and Windows, so this error means the log could not be moved aside when it exceeded maxBytes — typically a cross-device move, permission problem, or the destination path being occupied in a way Rename cannot replace (e.g. a directory).","triggerScenarios":"The primary log exceeds maxBytes and os.Rename to rotatedLogPath(primary) fails: rotated path exists as a directory, source and destination are on different filesystems, or permissions prevent the rename in either directory.","commonSituations":"An old rotated log file was replaced by a directory of the same name; the log lives in a container volume while the rotated name resolves elsewhere; running bd without write permission on the log directory after a user change.","solutions":["Check that the rotated path (e.g. server.log.1) is not a directory; remove or rename it.","Ensure the bd user has write permission on the directory containing the log (needed for rename).","Move the log directory onto a single filesystem, or delete/move the oversized log manually and restart.","Copy-then-delete manually if a cross-device rename is unavoidable: cp server.log server.log.1 && rm server.log."],"exampleFix":"// before (broken state)\n$ ls .beads/logs\nserver.log  server.log.1/   # rotated name is a directory\n// after\n$ rm -rf .beads/logs/server.log.1\n$ bd start   # rotation now succeeds","handlingStrategy":"validation","validationCode":"rotated := rotatedLogPath(primary)\nif info, err := os.Lstat(rotated); err == nil && info.IsDir() {\n    return fmt.Errorf(\"%s is a directory; cannot overwrite via rename\", rotated)\n}\n// source and destination must share a device\ns1, _ := os.Stat(filepath.Dir(primary))\ns2, _ := os.Stat(filepath.Dir(rotated))\nif s1 != nil && s2 != nil && !sameDevice(s1, s2) {\n    return fmt.Errorf(\"cross-device rename would fail\")\n}","typeGuard":null,"tryCatchPattern":"rotated, err := rotateLogIfOversized(primary, maxBytes)\nif err != nil {\n    var pe *fs.PathError\n    if errors.As(err, &pe) && errors.Is(pe.Err, syscall.EXDEV) {\n        // fall back to copy+delete\n    }\n    return err\n}","preventionTips":["Keep log and rotated log on the same filesystem","Never create directories named like the rotated log (e.g. server.log.1)","Maintain write permission on the log's parent directory","Prefer built-in rotation instead of external log rotators fighting over the same file"],"tags":["filesystem","logging","log-rotation","rename"],"backgroundTag":"file-rename-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}