{"record":{"id":"017f17b5b90cb461","repo":"benbjohnson/litestream","slug":"invalid-ltx-path-s","errorCode":null,"errorMessage":"invalid ltx path: %s","messagePattern":"invalid ltx path: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"nats/replica_client.go","lineNumber":264,"sourceCode":"\treturn nil\n}\n\n// ltxPath returns the object path for an LTX file.\nfunc (c *ReplicaClient) ltxPath(level int, minTXID, maxTXID ltx.TXID) string {\n\treturn litestream.LTXFilePath(c.Path, level, minTXID, maxTXID)\n}\n\n// parseLTXPath parses an LTX object path and returns level, minTXID, and maxTXID.\nfunc (c *ReplicaClient) parseLTXPath(objPath string) (level int, minTXID, maxTXID ltx.TXID, err error) {\n\t// Remove the base path prefix if present\n\tif c.Path != \"\" && strings.HasPrefix(objPath, c.Path+\"/\") {\n\t\tobjPath = strings.TrimPrefix(objPath, c.Path+\"/\")\n\t}\n\n\t// Expected format: \"ltx/<level>/<minTXID>-<maxTXID>.ltx\"\n\tparts := strings.Split(objPath, \"/\")\n\tif len(parts) < 3 || parts[0] != \"ltx\" {\n\t\treturn 0, 0, 0, fmt.Errorf(\"invalid ltx path: %s\", objPath)\n\t}\n\n\t// Parse level\n\tif level, err = strconv.Atoi(parts[1]); err != nil {\n\t\treturn 0, 0, 0, fmt.Errorf(\"invalid level in path %s: %w\", objPath, err)\n\t}\n\n\t// Parse filename (minTXID-maxTXID.ltx)\n\tfilename := parts[2]\n\tminTXIDVal, maxTXIDVal, err := ltx.ParseFilename(filename)\n\tif err != nil {\n\t\treturn 0, 0, 0, fmt.Errorf(\"invalid filename in path %s: %w\", objPath, err)\n\t}\n\n\treturn level, minTXIDVal, maxTXIDVal, nil\n}\n\n// LTXFiles returns an iterator of all LTX files on the replica for a given level.","sourceCodeStart":246,"sourceCodeEnd":282,"githubUrl":"https://github.com/benbjohnson/litestream/blob/4ed7a308f6271ebfd2b0a6e4b70b03011a37e4a3/nats/replica_client.go#L246-L282","documentation":"parseLTXPath converts a NATS object key into (level, minTXID, maxTXID) and expects the layout `ltx/<level>/<minTXID>-<maxTXID>.ltx` (after stripping the configured Path prefix). This error means the object key does not match that layout, so it cannot be interpreted as an LTX segment.","triggerScenarios":"LTXFiles → parseLTXPath on an object whose key has fewer than 3 slash-separated parts or whose first part is not `ltx`: foreign objects uploaded to the bucket, wrong Path prefix in config, or legacy/differently-named keys.","commonSituations":"Users or other tools storing non-LTX objects in the replica bucket; misconfigured `path` prefix in litestream config so the prefix strip fails; buckets shared between different tooling; keys created by older litestream layouts.","solutions":["Inspect the offending object key in the bucket (`nats object ls backups`) and remove non-LTX objects","Fix the `path` prefix in the litestream config so `ltx/...` keys parse after prefix stripping","Ensure litestream (not other tools) owns this bucket — use a dedicated bucket","If keys came from a legacy layout, re-snapshot with a full backup and `litestream reset`"],"exampleFix":"// config\n// before (prefix mismatch: objects stored under \"litestream/ltx/...\")\nurl: \"nats://host:4222/backups\"\n// after\npath: \"litestream\"\nurl: \"nats://host:4222/backups\"","handlingStrategy":"validation","validationCode":"// validate object keys before parsing\nparts := strings.Split(strings.TrimPrefix(key, prefix+\"/\"), \"/\")\nif len(parts) < 3 || parts[0] != \"ltx\" {\n\tlog.Printf(\"skipping non-LTX object %q in replica bucket\", key)\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep the replica bucket dedicated to litestream output","Set the `path` config option correctly so prefix stripping yields `ltx/...` keys","Audit bucket contents when sharing infrastructure with other tools"],"tags":["nats","ltx","path-parsing","config"],"backgroundTag":"invalid-argument-format","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"}