tailscale/tailscale · error
unsupport cert mode: %q
Error message
unsupport cert mode: %q
What it means
certProviderByCertMode switches on derper's --certmode flag; only "letsencrypt", "gcp" (Google Public CA ACME with EAB), and "manual" (files from --certdir) are implemented. Any other string reaches the default branch and returns this error (note the source's typo 'unsupport').
Source
Thrown at cmd/derper/cert.go:106
Key: keyBytes,
}
}
if hostname == "derp.tailscale.com" {
certManager.HostPolicy = prodAutocertHostPolicy
}
if email != "" {
certManager.Email = email
} else if hostname == "derp.tailscale.com" {
certManager.Email = "security@tailscale.com"
}
if ipCerts {
return newIPCertManager(dir, email, "", certManager)
}
return certManager, nil
case "manual":
return NewManualCertManager(dir, hostname)
default:
return nil, fmt.Errorf("unsupport cert mode: %q", mode)
}
}
type manualCertManager struct {
cert *tls.Certificate
hostname string // hostname or IP address of server
noHostname bool // whether hostname is an IP address
}
// NewManualCertManager returns a cert provider which read certificate by given hostname on create.
func NewManualCertManager(certdir, hostname string) (certProvider, error) {
keyname := unsafeHostnameCharacters.ReplaceAllString(hostname, "")
crtPath := filepath.Join(certdir, keyname+".crt")
keyPath := filepath.Join(certdir, keyname+".key")
cert, err := tls.LoadX509KeyPair(crtPath, keyPath)
hostnameIP := net.ParseIP(hostname) // or nil if hostname isn't an IP address
if err != nil {
// If the hostname is an IP address, automatically create aView on GitHub (pinned to cfe32b8be6)
Solutions
- Use --certmode=letsencrypt (ACME/Let's Encrypt, the usual default)
- Use --certmode=manual with cert/key files named <hostname>.crt/.key in --certdir
- Use --certmode=gcp together with --acme-eab-kid, --acme-eab-key and --acme-email
- Check derper --help for the exact flag spellings in your binary version
Example fix
# before: derper --hostname=derp.example.com --certmode=letsencrypt2 # after: derper --hostname=derp.example.com --certmode=letsencrypt
Defensive patterns
Strategy: validation
Validate before calling
var validCertModes = map[string]bool{"letsencrypt": true, "gcp": true, "manual": true}
if !validCertModes[mode] {
return fmt.Errorf("--certmode must be one of letsencrypt, gcp, manual; got %q", mode)
} Prevention
- Derive derper launch flags from a reviewed template, not blog posts
- Add a config lint step for the derper unit/manifest
- Check `derper --help` after version upgrades
When it happens
Trigger: Launching derper with a misspelled or removed --certmode value such as letsencrypt2, auto, self-signed, or a value from an outdated doc/tutorial.
Common situations: Copy-pasted derper commands from old blog posts; scripts pinning flags that a Tailscale version dropped; empty --certmode combined with custom flag handling that passes it through non-empty.
Related errors
- missing required --certdir flag
- --certmode=gcp requires --hostname to be a DNS name, not an
- --hostname is an IP address; use --certmode=manual for a sel
- can not load x509 key pair for hostname %q: %w
- --acme-ip-certs requires --certmode=letsencrypt
AI-assisted analysis of tailscale/tailscale@cfe32b8be6 (2026-08-15).
Data as JSON: /api/errors/cab98b8cec7fe7ac.
Report an issue: GitHub.