benbjohnson/litestream · error

invalid temp file name: %q

Error message

invalid temp file name: %q

What it means

tempFilenameFromCanonical derives a local temp-file name from a canonical SQLite file name by taking filepath.Base and rejecting names whose base is "." or a path separator. This error means the canonical name has no usable base component, so a deterministic temp file name cannot be built. It is raised before a FNV hash is computed.

Source

Thrown at vfs.go:379

	})
	return vfs.tempDir, vfs.tempDirErr
}

func (vfs *VFS) canonicalTempName(name string) string {
	if name == "" {
		return ""
	}
	name = filepath.Clean(name)
	if name == "." || name == string(filepath.Separator) {
		return ""
	}
	return name
}

func tempFilenameFromCanonical(canonical string) (string, error) {
	base := filepath.Base(canonical)
	if base == "." || base == string(filepath.Separator) {
		return "", fmt.Errorf("invalid temp file name: %q", canonical)
	}

	h := fnv.New64a()
	if _, err := h.Write([]byte(canonical)); err != nil {
		return "", fmt.Errorf("hash temp name: %w", err)
	}
	return fmt.Sprintf("%s-%016x", base, h.Sum64()), nil
}

func (vfs *VFS) openTempFile(name string, flags sqlite3vfs.OpenFlag) (sqlite3vfs.File, sqlite3vfs.OpenFlag, error) {
	dir, err := vfs.ensureTempDir()
	if err != nil {
		return nil, flags, err
	}
	deleteOnClose := flags&sqlite3vfs.OpenDeleteOnClose != 0 || name == ""
	var f *os.File
	var onClose func()
	if name == "" {

View on GitHub (pinned to 4ed7a308f6)

Solutions

  1. Remove trailing slashes from the database/journal path before opening it through the VFS.
  2. Pass a real file name, not a directory, to SQLite when using the litestream VFS.
  3. Log the offending canonical name (it is quoted in the error) and fix the code that generates it.
  4. If SQLite itself generates such names, capture a reproducible xOpen trace and report upstream.

Example fix

// before
name := "file:/var/tmp/dbdir/" // base == "."

// after
name := "file:/var/tmp/dbdir/app.db" // base == "app.db"
Defensive patterns

Strategy: validation

Validate before calling

func validCanonical(name string) bool {
    b := filepath.Base(name)
    return b != "." && b != string(filepath.Separator) && name != ""
}
// call before opening: if !validCanonical(name) { fix path }

Type guard

func isRealFilePath(p string) bool {
    return filepath.Base(p) != "." && filepath.Base(p) != string(filepath.Separator)
}

Prevention

When it happens

Trigger: SQLite passes an unusual canonical name to xOpen that triggers openTempFile, and the name's filepath.Base evaluates to "." (e.g. name ends with a separator or is ".") or equals the OS separator.

Common situations: Constructing file URIs with trailing slashes ("file:/tmp/foo/") so the base collapses to "."; passing a directory instead of a file path; bugs in wrapper code that strip the file name and hand the VFS only a directory path.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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