tailscale/tailscale · error
error parsing config file %s: unsupported \"version\" value
Error message
error parsing config file %s: unsupported \"version\" value %q; want \"alpha0\" for now
What it means
The config file declares a "version" string, but it is neither the currently-supported "alpha0" nor empty. Load only accepts exactly alpha0 at this stage of the format's lifecycle, so anything else — alpha1, 1.0, v2, experimental values — is rejected up front before any field decoding, protecting against silently misreading a newer dialect.
Source
Thrown at ipn/conffile/conffile.go:102
}
} else {
c.Std = c.Raw // config file must be valid JSON with ts_omit_hujsonconf
}
var ver struct {
Version string `json:"version"`
}
if err := json.Unmarshal(c.Std, &ver); err != nil {
if !buildfeatures.HasHuJSONConf {
return nil, fmt.Errorf("error parsing config file %s, which must be valid standard JSON: %w", path, err)
}
return nil, fmt.Errorf("error parsing config file %s: %w", path, err)
}
switch ver.Version {
case "":
return nil, fmt.Errorf("error parsing config file %s: no \"version\" field defined", path)
case "alpha0":
default:
return nil, fmt.Errorf("error parsing config file %s: unsupported \"version\" value %q; want \"alpha0\" for now", path, ver.Version)
}
c.Version = ver.Version
jd := json.NewDecoder(bytes.NewReader(c.Std))
jd.DisallowUnknownFields()
err = jd.Decode(&c.Parsed)
if err != nil {
return nil, fmt.Errorf("error parsing config file %s: %w", path, err)
}
if jd.More() {
return nil, fmt.Errorf("error parsing config file %s: trailing data after JSON object", path)
}
return &c, nil
}
View on GitHub (pinned to 6e0912f979)
Solutions
- Set the version to "alpha0" — the only value this build accepts
- If the file came from a newer tailscale, downgrade the config by hand: re-create it with alpha0 fields, or upgrade the binary to match the file
- Check for exact spelling/case: alpha0, all lowercase, no quotes mismatch
- Pin your config fixtures to the version supported by the oldest binary you deploy
Example fix
// before
{
"version": "alpha1",
"hostname": "node-1"
}
// after
{
"version": "alpha0",
"hostname": "node-1"
} Defensive patterns
Strategy: validation
Validate before calling
func supportedVersion(v string) bool {
return v == "alpha0"
} Type guard
func versionSupportedByThisBuild(b []byte) bool {
var v struct {
Version string `json:"version"`
}
_ = json.Unmarshal(b, &v)
return supportedVersion(v.Version)
} Try / catch
if v, ok := versionOf(raw); ok && !supportedVersion(v) {
return fmt.Errorf("config version %q unsupported by this binary; upgrade binary or pin file to alpha0", v)
}
cfg, err := conffile.Load(path) Prevention
- Pin configs to the version of the oldest binary in the fleet
- Automate config regeneration on binary upgrades/downgrades
- Copy the version string verbatim from shipped examples; never retype it
- Add a CI check comparing config version against the release's supported set
When it happens
Trigger: A config written for a different (usually newer or aspirational) version of the format, e.g. "version": "alpha1" or "version": "1.0"; downgrading: config file produced by a newer tailscale whose format version bumped past alpha0, then loaded by an older build; typos like "alphaO" (letter O) or "Alpha0".
Common situations: Rolling back a binary while keeping /etc/tailscale config from the newer release; documentation/tutorial referencing a version string that never shipped this build; CI fixtures copied from main-branch tests into older release tests.
Related errors
- unsupported config file version %q
- error parsing config file %s: no \"version\" field defined
- getting serve config: %w
- route %s has non-address bits set; expected %s
- config file loading not supported on %q
AI-assisted analysis of tailscale/tailscale@6e0912f979 (2026-08-18).
Data as JSON: /api/errors/d92a68b2dc07992e.
Report an issue: GitHub.