benbjohnson/litestream · error

invalid ltx path

Error message

invalid ltx path: %s

What it means

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.

Solutions

  1. Inspect the offending object key in the bucket (`nats object ls backups`) and remove non-LTX objects
  2. Fix the `path` prefix in the litestream config so `ltx/...` keys parse after prefix stripping
  3. Ensure litestream (not other tools) owns this bucket — use a dedicated bucket
  4. If keys came from a legacy layout, re-snapshot with a full backup and `litestream reset`

Example fix

// config
// before (prefix mismatch: objects stored under "litestream/ltx/...")
url: "nats://host:4222/backups"
// after
path: "litestream"
url: "nats://host:4222/backups"
Defensive patterns

Strategy: validation

Validate before calling

// validate object keys before parsing
parts := strings.Split(strings.TrimPrefix(key, prefix+"/"), "/")
if len(parts) < 3 || parts[0] != "ltx" {
	log.Printf("skipping non-LTX object %q in replica bucket", key)
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


AI-assisted analysis of benbjohnson/litestream@4ed7a308f6 (2026-09-06). Data as JSON: /api/errors/017f17b5b90cb461. Report an issue: GitHub.

Appendix: source

Thrown at nats/replica_client.go:264

	return nil
}

// ltxPath returns the object path for an LTX file.
func (c *ReplicaClient) ltxPath(level int, minTXID, maxTXID ltx.TXID) string {
	return litestream.LTXFilePath(c.Path, level, minTXID, maxTXID)
}

// parseLTXPath parses an LTX object path and returns level, minTXID, and maxTXID.
func (c *ReplicaClient) parseLTXPath(objPath string) (level int, minTXID, maxTXID ltx.TXID, err error) {
	// Remove the base path prefix if present
	if c.Path != "" && strings.HasPrefix(objPath, c.Path+"/") {
		objPath = strings.TrimPrefix(objPath, c.Path+"/")
	}

	// Expected format: "ltx/<level>/<minTXID>-<maxTXID>.ltx"
	parts := strings.Split(objPath, "/")
	if len(parts) < 3 || parts[0] != "ltx" {
		return 0, 0, 0, fmt.Errorf("invalid ltx path: %s", objPath)
	}

	// Parse level
	if level, err = strconv.Atoi(parts[1]); err != nil {
		return 0, 0, 0, fmt.Errorf("invalid level in path %s: %w", objPath, err)
	}

	// Parse filename (minTXID-maxTXID.ltx)
	filename := parts[2]
	minTXIDVal, maxTXIDVal, err := ltx.ParseFilename(filename)
	if err != nil {
		return 0, 0, 0, fmt.Errorf("invalid filename in path %s: %w", objPath, err)
	}

	return level, minTXIDVal, maxTXIDVal, nil
}

// LTXFiles returns an iterator of all LTX files on the replica for a given level.

View on GitHub (pinned to 4ed7a308f6)