{"record":{"id":"0d07a181533e7f6e","repo":"juanfont/headscale","slug":"no-ipv4-or-ipv6-prefix-configured-minimum-one-pre","errorCode":null,"errorMessage":"no IPv4 or IPv6 prefix configured, minimum one prefix is required","messagePattern":"no IPv4 or IPv6 prefix configured, minimum one prefix is required","errorType":"validation","errorClass":"ErrNoPrefixConfigured","httpStatus":null,"severity":"critical","filePath":"hscontrol/types/config.go","lineNumber":43,"sourceCode":")\n\nconst (\n\tPKCEMethodPlain string = \"plain\"\n\tPKCEMethodS256  string = \"S256\"\n\n\tdefaultNodeStoreBatchSize = 100\n)\n\nvar (\n\terrOidcMutuallyExclusive     = errors.New(\"oidc_client_secret and oidc_client_secret_path are mutually exclusive\")\n\terrOIDCIssuerInvalid         = errors.New(\"oidc.issuer must be a valid http(s) URL\")\n\terrOIDCClientIDRequired      = errors.New(\"oidc.client_id is required when oidc.issuer is set\")\n\terrOIDCClientSecretRequired  = errors.New(\"oidc.client_secret or oidc.client_secret_path is required when oidc.issuer is set\")\n\terrServerURLSuffix           = errors.New(\"server_url cannot be part of base_domain in a way that could make the DERP and headscale server unreachable\")\n\terrServerURLSame             = errors.New(\"server_url cannot use the same domain as base_domain in a way that could make the DERP and headscale server unreachable\")\n\terrInvalidPKCEMethod         = errors.New(\"pkce.method must be either 'plain' or 'S256'\")\n\terrTrustedProxyZeroRange     = errors.New(\"0.0.0.0/0 and ::/0 are not allowed\")\n\tErrNoPrefixConfigured        = errors.New(\"no IPv4 or IPv6 prefix configured, minimum one prefix is required\")\n\tErrInvalidAllocationStrategy = errors.New(\"invalid prefix allocation strategy\")\n)\n\ntype IPAllocationStrategy string\n\nconst (\n\tIPAllocationStrategySequential IPAllocationStrategy = \"sequential\"\n\tIPAllocationStrategyRandom     IPAllocationStrategy = \"random\"\n)\n\ntype PolicyMode string\n\nconst (\n\tPolicyModeDB   = \"database\"\n\tPolicyModeFile = \"file\"\n)\n\n// EphemeralConfig contains configuration for ephemeral node lifecycle.","sourceCodeStart":25,"sourceCodeEnd":61,"githubUrl":"https://github.com/juanfont/headscale/blob/565fd254d06c4c7f9a8cad1714a43445c79ba420/hscontrol/types/config.go#L25-L61","documentation":"ErrNoPrefixConfigured is returned from hscontrol/types/config.go:1134 during prefix resolution when the ip_prefixes list yields no usable prefix. Every node in a tailnet must get an IP from the CGNAT range (default 100.64.0.0/10 and fd7a:115c:a1e0::/48), so with zero prefixes the server cannot allocate addresses and refuses to start. This is a fatal config-validation error, not a runtime one.","triggerScenarios":"Setting ip_prefixes: [] (empty list) in config.yaml; listing only prefixes that are filtered out (e.g. invalid families or unusable ranges) so the surviving list is empty; then calling LoadConfig / starting `headscale serve`.","commonSituations":"Commenting out the ip_prefixes block while experimenting and accidentally leaving an empty key; narrowing prefixes to avoid a CGNAT clash (per the disable-ipv4 nodeAttr docs) and removing both families; config migration between headscale versions where the key name or defaults changed.","solutions":["Restore at least one prefix in config.yaml: ip_prefixes: [\"100.64.0.0/10\"] (IPv4 CGNAT) and/or [\"fd7a:115c:a1e0::/48\"] (IPv6 ULA)","If you intentionally want no IPv4, keep the IPv6 prefix fd7a:115c:a1e0::/48 so allocation still works","Validate with `headscale config verify` before restarting the service"],"exampleFix":"# before\nip_prefixes: []\n\n# after\nip_prefixes:\n  - fd7a:115c:a1e0::/48\n  - 100.64.0.0/10","handlingStrategy":"validation","validationCode":"// ensure at least one prefix is configured before starting\nif len(cfg.Prefixes.V4) == 0 && len(cfg.Prefixes.V6) == 0 {\n\treturn errors.New(\"ip_prefixes must contain at least one of 100.64.0.0/10 or fd7a:115c:a1e0::/48\")\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep the default ip_prefixes block in config.yaml unless you deliberately replace it","When narrowing prefixes to dodge CGNAT conflicts, always leave one family configured","Validate config with `headscale config verify` after edits"],"tags":["config","ip-allocation","validation","startup"],"backgroundTag":null,"analyzedSha":"565fd254d06c4c7f9a8cad1714a43445c79ba420","analyzedAt":"2026-08-15T13:12:30.133Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}