{"record":{"id":"3ace0b9d096fc0ca","repo":"juanfont/headscale","slug":"path-cannot-be-empty","errorCode":null,"errorMessage":"path cannot be empty","messagePattern":"path cannot be empty","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"hscontrol/db/sqliteconfig/config.go","lineNumber":14,"sourceCode":"// Package sqliteconfig provides type-safe configuration for SQLite databases\n// with proper enum validation and URL generation for modernc.org/sqlite driver.\npackage sqliteconfig\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"slices\"\n\t\"strings\"\n)\n\n// Errors returned by config validation.\nvar (\n\tErrPathEmpty           = errors.New(\"path cannot be empty\")\n\tErrBusyTimeoutNegative = errors.New(\"busy_timeout must be >= 0\")\n\tErrInvalidJournalMode  = errors.New(\"invalid journal_mode\")\n\tErrInvalidAutoVacuum   = errors.New(\"invalid auto_vacuum\")\n\tErrWALAutocheckpoint   = errors.New(\"wal_autocheckpoint must be >= -1\")\n\tErrInvalidSynchronous  = errors.New(\"invalid synchronous\")\n\tErrInvalidTxLock       = errors.New(\"invalid txlock\")\n)\n\nconst (\n\t// DefaultBusyTimeout is the default busy timeout in milliseconds.\n\tDefaultBusyTimeout = 10000\n)\n\n// JournalMode represents SQLite journal_mode pragma values.\n// Journal modes control how SQLite handles write transactions and crash recovery.\n//\n// Performance vs Durability Tradeoffs:\n//","sourceCodeStart":1,"sourceCodeEnd":32,"githubUrl":"https://github.com/juanfont/headscale/blob/565fd254d06c4c7f9a8cad1714a43445c79ba420/hscontrol/db/sqliteconfig/config.go#L1-L32","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"# before\ndatabase:\n  type: sqlite\n  sqlite:\n    path: \"\"\n\n# after\ndatabase:\n  type: sqlite\n  sqlite:\n    path: /var/lib/headscale/headscale.db","handlingStrategy":"validation","validationCode":"func requireSQLitePath(path string) error {\n    if strings.TrimSpace(path) == \"\" {\n        return sqliteconfig.ErrPathEmpty\n    }\n    return nil\n}","typeGuard":"func hasSQLitePath(path string) bool { return strings.TrimSpace(path) != \"\" }","tryCatchPattern":"url, err := cfg.URL() // or Validate()\nif err != nil {\n    if errors.Is(err, sqliteconfig.ErrPathEmpty) {\n        return fmt.Errorf(\"database.sqlite.path is required when type is sqlite\")\n    }\n    return err\n}","preventionTips":["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"],"tags":["sqlite","config","validation","database","headscale"],"backgroundTag":null,"analyzedSha":"565fd254d06c4c7f9a8cad1714a43445c79ba420","analyzedAt":"2026-08-15T13:12:30.133Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}