juanfont/headscale · critical
path cannot be empty
Error message
path cannot be empty
What it means
Exported validation error from hscontrol/db/sqliteconfig, returned when building a modernc.org/sqlite DSN with an empty path. The package turns a config struct into a validated SQLite URL; a database with no file location is rejected before the driver is ever invoked.
Source
Thrown at hscontrol/db/sqliteconfig/config.go:14
// Package sqliteconfig provides type-safe configuration for SQLite databases
// with proper enum validation and URL generation for modernc.org/sqlite driver.
package sqliteconfig
import (
"errors"
"fmt"
"slices"
"strings"
)
// Errors returned by config validation.
var (
ErrPathEmpty = errors.New("path cannot be empty")
ErrBusyTimeoutNegative = errors.New("busy_timeout must be >= 0")
ErrInvalidJournalMode = errors.New("invalid journal_mode")
ErrInvalidAutoVacuum = errors.New("invalid auto_vacuum")
ErrWALAutocheckpoint = errors.New("wal_autocheckpoint must be >= -1")
ErrInvalidSynchronous = errors.New("invalid synchronous")
ErrInvalidTxLock = errors.New("invalid txlock")
)
const (
// DefaultBusyTimeout is the default busy timeout in milliseconds.
DefaultBusyTimeout = 10000
)
// JournalMode represents SQLite journal_mode pragma values.
// Journal modes control how SQLite handles write transactions and crash recovery.
//
// Performance vs Durability Tradeoffs:
//View on GitHub (pinned to 565fd254d0)
Solutions
- Set database.sqlite.path in config.yaml (e.g. /var/lib/headscale/headscale.db) or HEADSCALE_DB_PATH
- If embedding sqliteconfig, default the Path field before calling Validate
- Check container compose files for empty-string env overrides
Example fix
# before
database:
type: sqlite
sqlite:
path: ""
# after
database:
type: sqlite
sqlite:
path: /var/lib/headscale/headscale.db Defensive patterns
Strategy: validation
Validate before calling
func requireSQLitePath(path string) error {
if strings.TrimSpace(path) == "" {
return sqliteconfig.ErrPathEmpty
}
return nil
} Type guard
func hasSQLitePath(path string) bool { return strings.TrimSpace(path) != "" } Try / catch
url, err := cfg.URL() // or Validate()
if err != nil {
if errors.Is(err, sqliteconfig.ErrPathEmpty) {
return fmt.Errorf("database.sqlite.path is required when type is sqlite")
}
return err
} Prevention
- Default database.sqlite.path in config templates; fail CI on empty values
- Check container env overrides (HEADSCALE_DB_PATH) for empty strings
- In Go code, call sqliteconfig Validate() before building the DSN
When it happens
Trigger: Constructing a sqliteconfig.Config with Path == "" (e.g. database.sqlite.path unset in headscale config, or the HEADSCALE_DB_PATH env var set to an empty string) and calling its Validate/URL-generation method.
Common situations: Config templating that leaves the sqlite.path key blank when database.type is sqlite; overriding the DB path env var with an empty value in a container; tests building configs from partial structs.
Related errors
- busy_timeout must be >= 0
- database type not supported
- foreign key constraints violated
- wildcard (*) is not supported as SSH destination
- is above the max (168h)
AI-assisted analysis of juanfont/headscale@565fd254d0 (2026-08-15).
Data as JSON: /api/errors/3ace0b9d096fc0ca.
Report an issue: GitHub.