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

  1. Set the version to "alpha0" — the only value this build accepts
  2. 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
  3. Check for exact spelling/case: alpha0, all lowercase, no quotes mismatch
  4. 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

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


AI-assisted analysis of tailscale/tailscale@6e0912f979 (2026-08-18). Data as JSON: /api/errors/d92a68b2dc07992e. Report an issue: GitHub.