JuliusBrussee/caveman · error

refusing non-regular file

Error message

refusing non-regular file

What it means

secureSQLiteFile refuses to secure anything that is not a plain regular file: if Lstat (without following symlinks) shows the path is a symlink or otherwise non-regular, it returns 'refusing non-regular file'. This is a security guard preventing the CCR store from following a planted symlink when applying permissions or writing data.

Solutions

  1. Replace the symlink with a real file: copy the target's contents to a regular file at that path (if intended) or remove the symlink and let Open create a fresh db
  2. Verify with ls -la / stat that the path is a regular file
  3. Never symlink CCR store files into sync folders (Dropbox/Google Drive); move the whole store directory instead
  4. Remove any fifo/socket/directory occupying the db path and re-run

Example fix

// before
$ ln -s /mnt/sync/recovery.db /var/lib/ccr/recovery.db
// after
$ rm /var/lib/ccr/recovery.db
$ cp /mnt/sync/recovery.db /var/lib/ccr/recovery.db && chmod 600 /var/lib/ccr/recovery.db
Defensive patterns

Strategy: validation

Validate before calling

func isRegularFile(p string) bool {
    fi, err := os.Lstat(p)
    return err == nil && fi.Mode().IsRegular() && fi.Mode()&os.ModeSymlink == 0
}

Try / catch

err := ccr.Open(dbPath)
if err != nil && strings.Contains(err.Error(), "refusing non-regular file") {
    return fmt.Errorf("%s (or a sidecar) is a symlink/special file; replace with a real file: %w", dbPath, err)
}

Prevention

When it happens

Trigger: The sqlite path (or a -wal/-shm sidecar path) is a symlink pointing elsewhere; the 'file' is actually a directory, fifo, socket, or device node; an attacker or careless script replaced the db file with a symlink before Open.

Common situations: User symlinked the database from another location (e.g. ln -s ~/dropbox/recovery.db) to sync it; provisioning scripts created a fifo/socket at the db path; a broken deployment replaced the file with a directory.

Understand the failure class

Background: Path traversal blocked: "path escapes the workspace" and "outside site root" errors when a path will not stay inside its allowed directory — this error's family across 26 libraries.

Related errors


AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20). Data as JSON: /api/errors/a1f66198d8176de5. Report an issue: GitHub.

Appendix: source

Thrown at engine/ccr/store_sqlite.go:352

	info, err := os.Lstat(path)
	if errors.Is(err, os.ErrNotExist) && create {
		createErr := createSQLiteFile(path)
		if createErr == nil {
			return nil
		}
		if !errors.Is(createErr, os.ErrExist) {
			return createErr
		}
		info, err = os.Lstat(path)
	}
	if errors.Is(err, os.ErrNotExist) && !create {
		return nil
	}
	if err != nil {
		return err
	}
	if info.Mode()&os.ModeSymlink != 0 || !info.Mode().IsRegular() {
		return fmt.Errorf("refusing non-regular file")
	}
	err = chmodSQLiteFile(path, info)
	if errors.Is(err, os.ErrNotExist) && !create {
		// The sidecar vanished while securing it — a concurrent process
		// checkpointed the WAL and removed it. Nothing left to secure.
		return nil
	}
	if err != nil {
		return err
	}
	secured, err := os.Lstat(path)
	if errors.Is(err, os.ErrNotExist) && !create {
		return nil
	}
	if err != nil {
		return err
	}
	if !os.SameFile(info, secured) {

View on GitHub (pinned to 3ee70a1026)