{"record":{"id":"a7397a7dfb64f241","repo":"juanfont/headscale","slug":"getting-derpmap-w","errorCode":null,"errorMessage":"getting DERPMap: %w","messagePattern":"getting DERPMap: %w","errorType":"console","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"hscontrol/app.go","lineNumber":560,"sourceCode":"\t\tMsg(\"Clients with a lower minimum version will be rejected\")\n\n\th.mapBatcher = mapper.NewBatcherAndMapper(h.cfg, h.state)\n\n\th.mapBatcher.Start()\n\tdefer h.mapBatcher.Close()\n\n\tif h.cfg.DERP.ServerEnabled {\n\t\t// When embedded DERP is enabled we always need a STUN server\n\t\tif h.cfg.DERP.STUNAddr == \"\" {\n\t\t\treturn errSTUNAddressNotSet\n\t\t}\n\n\t\tgo h.DERPServer.ServeSTUN()\n\t}\n\n\tderpMap, err := derp.GetDERPMap(h.cfg.DERP)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"getting DERPMap: %w\", err)\n\t}\n\n\tif h.cfg.DERP.ServerEnabled && h.cfg.DERP.AutomaticallyAddEmbeddedDerpRegion {\n\t\tregion, _ := h.DERPServer.GenerateRegion()\n\t\tderpMap.Regions[region.RegionID] = &region\n\t}\n\n\tif len(derpMap.Regions) == 0 {\n\t\treturn errEmptyInitialDERPMap\n\t}\n\n\th.state.SetDERPMap(derpMap)\n\n\t// Start ephemeral node garbage collector and schedule all nodes\n\t// that are already in the database and ephemeral. If they are still\n\t// around between restarts, they will reconnect and the GC will\n\t// be cancelled.\n\tgo h.ephemeralGC.Start()","sourceCodeStart":542,"sourceCodeEnd":578,"githubUrl":"https://github.com/juanfont/headscale/blob/565fd254d06c4c7f9a8cad1714a43445c79ba420/hscontrol/app.go#L542-L578","documentation":"derp.GetDERPMap(h.cfg.DERP) failed while assembling the initial DERP map at startup (hscontrol/derp/derp.go:94). The function merges an inline DERPMap config, every entry in derp.urls (fetched over HTTP), and every entry in derp.paths (loaded from disk); any single source failing aborts startup. Typical wrapped causes are an unreachable/invalid URL, an HTTP fetch error, or a path that is missing/unparseable.","triggerScenarios":"A derp.urls entry that is not a valid URL or returns non-200/unreachable (air-gapped host fetching the default Tailscale DERP map), TLS failures, a derp.paths file that does not exist or is invalid JSON/YAML, or a parse failure of the downloaded map.","commonSituations":"Offline/air-gapped deployments keeping the default derp.urls; a typo'd custom DERP map URL; DERP map file with schema drift after upgrading headscale; firewall blocking the control host's egress; self-hosted map served with a bad certificate.","solutions":["Check the wrapped error — it names whether the failure came from a URL or a path","For air-gapped installs, remove default derp.urls and provide a local file via derp.paths instead","curl -fsSL <url> each configured URL from the headscale host to verify reachability and JSON validity","Validate path-based maps: jq <path> must parse and match the DERPMap schema (Regions with Nodes)"],"exampleFix":"# before (air-gapped host, default urls unreachable)\nderp:\n  urls:\n    - https://controlplane.tailscale.com/derpmap/default\n\n# after\nderp:\n  urls: []\n  paths:\n    - /etc/headscale/derpmap.json","handlingStrategy":"validation","validationCode":"for _, u := range cfg.DERP.URLs {\n    resp, err := http.Head(u) // or GET with timeout\n    if err != nil || resp.StatusCode != 200 {\n        return fmt.Errorf(\"DERP map URL unreachable: %s\", u)\n    }\n}\nfor _, p := range cfg.DERP.Paths {\n    if _, err := os.Stat(p); err != nil {\n        return fmt.Errorf(\"DERP map path missing: %s\", p)\n    }\n}","typeGuard":null,"tryCatchPattern":"if _, err := derp.GetDERPMap(h.cfg.DERP); err != nil {\n    // single-source failure aborts startup; check wrapped error to see if it was\n    // a URL (network) or path (filesystem) source and fix that one source\n    return fmt.Errorf(\"getting DERPMap: %w\", err)\n}","preventionTips":["On air-gapped hosts, replace derp.urls with a local derp.paths file","Serve custom DERP maps from highly available endpoints with valid TLS","Validate every configured URL/path from the headscale host before restart"],"tags":["derp","derpmap","network","configuration","startup"],"backgroundTag":null,"analyzedSha":"565fd254d06c4c7f9a8cad1714a43445c79ba420","analyzedAt":"2026-08-15T13:12:30.133Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}