{"record":{"id":"3416f9ff861eaa13","repo":"benbjohnson/litestream","slug":"failed-to-calculate-relative-path-for-s-w","errorCode":null,"errorMessage":"failed to calculate relative path for %s: %w","messagePattern":"failed to calculate relative path for (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/litestream/main.go","lineNumber":871,"sourceCode":"\t\tif mp := db.MetaPath(); mp != \"\" {\n\t\t\tif existingDB, exists := metaPaths[mp]; exists {\n\t\t\t\treturn nil, fmt.Errorf(\"meta-path collision: databases %s and %s would share meta-path %s, causing replication state corruption\", existingDB, dbPath, mp)\n\t\t\t}\n\t\t\tmetaPaths[mp] = dbPath\n\t\t}\n\n\t\tdbs = append(dbs, db)\n\t}\n\n\treturn dbs, nil\n}\n\n// newDBFromDirectoryEntry creates a DB instance for a database discovered via directory replication.\nfunc newDBFromDirectoryEntry(dbc *DBConfig, dirPath, dbPath string) (*litestream.DB, error) {\n\t// Calculate relative path from directory root\n\trelPath, err := filepath.Rel(dirPath, dbPath)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to calculate relative path for %s: %w\", dbPath, err)\n\t}\n\n\t// Create a copy of the config for the discovered database\n\tdbConfigCopy := *dbc\n\tdbConfigCopy.Path = dbPath\n\tdbConfigCopy.Dir = \"\"          // Clear dir field for individual DB\n\tdbConfigCopy.Pattern = \"\"      // Clear pattern field\n\tdbConfigCopy.Recursive = false // Clear recursive flag\n\tdbConfigCopy.Watch = false     // Individual DBs do not watch directories\n\n\t// Ensure every database discovered beneath a directory receives a unique\n\t// metadata path. Without this, all databases share the same meta-path and\n\t// clobber each other's replication state.\n\tswitch {\n\tcase dbc.MetaDir != nil:\n\t\tbaseMetaDir, err := expand(*dbc.MetaDir)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to expand meta dir for %s: %w\", dbPath, err)","sourceCodeStart":853,"sourceCodeEnd":889,"githubUrl":"https://github.com/benbjohnson/litestream/blob/4ed7a308f6271ebfd2b0a6e4b70b03011a37e4a3/cmd/litestream/main.go#L853-L889","documentation":"newDBFromDirectoryEntry computes each database's path relative to the replication directory root (used to namespace meta paths and replica paths). filepath.Rel fails when the two paths cannot be related — typically when dbPath is not actually under dirPath (e.g. via symlink resolution) or a path is malformed. The failure is wrapped with the database path.","triggerScenarios":"filepath.Rel(dirPath, dbPath) returns an error: dbPath is not a subpath of dirPath (rooted vs relative mismatch, symlinked directory resolved differently), or one of the paths is empty/malformed.","commonSituations":"Scanned directory is itself a symlink so FindSQLiteDatabases returns paths that don't lexically sit under dirPath; mixing absolute dir with relative db paths; platform path-separator mismatch.","solutions":["Ensure `dir` in the config is the real (non-symlink) absolute path of the directory.","Use filepath.EvalSymlinks on the directory before configuring so dirPath and discovered dbPath share a base.","Check the wrapped filepath.Rel error message for the exact two paths involved and align them."],"exampleFix":"// before\ndirPath, _ := expand(dbc.Dir) // /data is a symlink to /mnt/data\n\n// after\ndirPath, _ := expand(dbc.Dir)\nif resolved, err := filepath.EvalSymlinks(dirPath); err == nil {\n    dirPath = resolved\n}","handlingStrategy":"validation","validationCode":"if resolved, err := filepath.EvalSymlinks(dirPath); err == nil {\n    dirPath = resolved\n}\nif _, err := filepath.Rel(dirPath, dbPath); err != nil {\n    return fmt.Errorf(\"db %s is not under dir %s\", dbPath, dirPath)\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Configure litestream with the real, symlink-resolved, absolute directory path.","Avoid scanning directories that mix absolute and relative path bases.","Test filepath.Rel on your layout before deploying."],"tags":["litestream","filesystem","path","symlink"],"backgroundTag":"invalid-argument-value","analyzedSha":"4ed7a308f6271ebfd2b0a6e4b70b03011a37e4a3","analyzedAt":"2026-09-06T18:29:25.564Z","contentChangedAt":"2026-09-06T18:29:25.564Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}