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 a

View on GitHub (pinned to cfe32b8be6)

Solutions

  1. Use --certmode=letsencrypt (ACME/Let's Encrypt, the usual default)
  2. Use --certmode=manual with cert/key files named <hostname>.crt/.key in --certdir
  3. Use --certmode=gcp together with --acme-eab-kid, --acme-eab-key and --acme-email
  4. 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

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


AI-assisted analysis of tailscale/tailscale@cfe32b8be6 (2026-08-15). Data as JSON: /api/errors/cab98b8cec7fe7ac. Report an issue: GitHub.