{"record":{"id":"657660a81d085773","repo":"juanfont/headscale","slug":"init-state-w","errorCode":null,"errorMessage":"init state: %w","messagePattern":"init state: %w","errorType":"console","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"hscontrol/app.go","lineNumber":125,"sourceCode":"\ttailsqlTSKey     = envknob.String(\"TS_AUTHKEY\")\n\tdumpConfig       = envknob.Bool(\"HEADSCALE_DEBUG_DUMP_CONFIG\")\n)\n\nfunc NewHeadscale(cfg *types.Config) (*Headscale, error) {\n\tvar err error\n\n\tif profilingEnabled {\n\t\truntime.SetBlockProfileRate(1)\n\t}\n\n\tnoisePrivateKey, err := readOrCreatePrivateKey(cfg.NoisePrivateKeyPath)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"reading or creating Noise protocol private key: %w\", err)\n\t}\n\n\ts, err := state.NewState(cfg)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"init state: %w\", err)\n\t}\n\n\tapp := Headscale{\n\t\tcfg:               cfg,\n\t\tnoisePrivateKey:   noisePrivateKey,\n\t\tclientStreamsOpen: sync.WaitGroup{},\n\t\tstate:             s,\n\t}\n\n\tif len(cfg.TrustedProxies) > 0 {\n\t\tapp.realIPMiddleware, err = trustedProxyRealIP(cfg.TrustedProxies)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"building trusted_proxies middleware: %w\", err)\n\t\t}\n\t}\n\n\t// Initialize ephemeral garbage collector\n\tephemeralGC := db.NewEphemeralGarbageCollector(func(ni types.NodeID) {","sourceCodeStart":107,"sourceCodeEnd":143,"githubUrl":"https://github.com/juanfont/headscale/blob/565fd254d06c4c7f9a8cad1714a43445c79ba420/hscontrol/app.go#L107-L143","documentation":"state.NewState(cfg) failed during headscale startup. State is the central coordinator (per AGENTS.md, all cross-subsystem operations go through hscontrol/state); its constructor opens the database, runs migrations, seeds policy, and initializes the in-memory NodeStore. The wrapped error identifies which stage broke — most commonly database open/migration (bad db.type/db.path, unreachable PostgreSQL, failed migration) or invalid policy/config values validated at construction time.","triggerScenarios":"Configured database unavailable (PostgreSQL connection refused, wrong credentials), SQLite db_path in an unwritable location, a migration failing against a corrupted or partially-upgraded schema, or policy/config validation rejecting values inside NewState.","commonSituations":"PostgreSQL not started before headscale; db path on a read-only volume; upgrading headscale across versions against an old database whose schema was hand-modified; wrong db.type spelling in config; SQLite file locked by another headscale instance.","solutions":["Read the wrapped error — 'init state' chains the real cause (db open, migration name, policy parse)","For PostgreSQL: verify connectivity with the same DSN (`psql <dsn> -c 'select 1'`) and credentials","For SQLite: ensure db_path's directory exists and is writable by the headscale user; remove stale lock files from a crashed instance","Restore from backup if a migration fails mid-way; never skip failed migrations (migration rules in AGENTS.md are load-bearing)"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// For PostgreSQL configs, verify connectivity before handing off to headscale\nif cfg.Database.Type == \"postgres\" {\n    if err := pingDB(cfg.Database.Postgres.Host, cfg.Database.Postgres.User); err != nil {\n        return fmt.Errorf(\"database unreachable: %w\", err)\n    }\n}","typeGuard":null,"tryCatchPattern":"if _, err := state.NewState(cfg); err != nil {\n    // unwrapping reveals db open vs migration vs policy validation;\n    // migration failures must never be retried with FKs disabled or orders changed\n    return fmt.Errorf(\"init state: %w\", err)\n}","preventionTips":["Start/health-check the database before headscale (init ordering in containers/Pods)","Back up the database before upgrading headscale versions","Keep db.path on a writable persistent volume owned by the headscale user"],"tags":["startup","database","state","migrations","configuration"],"backgroundTag":null,"analyzedSha":"565fd254d06c4c7f9a8cad1714a43445c79ba420","analyzedAt":"2026-08-15T13:12:30.133Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}