{"record":{"id":"973d3c8dc7ed96a4","repo":"tailscale/tailscale","slug":"acme-account-key-w","errorCode":null,"errorMessage":"ACME account key: %w","messagePattern":"ACME account key: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/derper/ipcert.go","lineNumber":91,"sourceCode":"\tflight      chan struct{} // non-nil while an issuance is running; closed when it finishes\n\tflightErr   error         // result of the last finished issuance\n\tnextAttempt time.Time     // earliest time of the next issuance attempt, after a failure\n\tretryDelay  time.Duration // backoff to apply after the next failure\n}\n\n// newIPCertManager returns an ipCertManager storing its ACME account\n// key and issued certificates in certdir.\n//\n// If directoryURL is empty, the LetsEncrypt production directory is\n// used; tests point it at a fake ACME server. If next is non-nil,\n// connections with a DNS name in the SNI are served by it.\nfunc newIPCertManager(certdir, email, directoryURL string, next certProvider) (*ipCertManager, error) {\n\tif err := os.MkdirAll(certdir, 0700); err != nil {\n\t\treturn nil, err\n\t}\n\taccountKey, err := loadOrCreateAccountKey(filepath.Join(certdir, \"acme-account.key\"))\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"ACME account key: %w\", err)\n\t}\n\tm := &ipCertManager{\n\t\tcertDir: certdir,\n\t\temail:   email,\n\t\tclient: &acme.Client{\n\t\t\tKey:          accountKey,\n\t\t\tDirectoryURL: directoryURL,\n\t\t\tUserAgent:    \"tailscale-derper\",\n\t\t},\n\t\tnext:   next,\n\t\tcerts:  make(map[netip.Addr]*ipCertEntry),\n\t\ttokens: make(map[string]string),\n\t}\n\tif next != nil {\n\t\tm.nextTLS = next.TLSConfig()\n\t}\n\tgo m.renewLoop()\n\treturn m, nil","sourceCodeStart":73,"sourceCodeEnd":109,"githubUrl":"https://github.com/tailscale/tailscale/blob/cfe32b8be6a33f8e24fbc369cbfbf7c729d9e042/cmd/derper/ipcert.go#L73-L109","documentation":"Returned by newIPCertManager when loadOrCreateAccountKey cannot read, parse, or create the ACME account key at <certdir>/acme-account.key. The %w wraps the underlying cause: invalid PEM, x509.ParseECPrivateKey failure (key is not ECDSA P-256 material), or a filesystem error creating a new key (EACCES, read-only volume, disk full).","triggerScenarios":"Starting derper with IP cert mode (newIPCertManager) where certdir exists but acme-account.key is unreadable or corrupt, where the file holds a non-EC key (e.g. RSA or a JWK dumped by another ACME tool), or where the process lacks write permission to generate a fresh key. Also triggers when certdir is on a read-only mount (some container setups).","commonSituations":"Reusing a certdir previously written by certbot or another ACME client; running derper as a different user than the one that owns the directory; containers with a read-only or non-persistent volume; disk full at first launch.","solutions":["Read the wrapped error to distinguish corrupt key (pem/parse errors) from permissions (os permission denied).","If the key file is corrupt or foreign, delete <certdir>/acme-account.key; derper generates a new P-256 key and re-registers with the ACME CA automatically.","Fix ownership/permissions: chown the certdir to the derper user and keep it 0700.","Ensure the volume is writable and has space if running in Docker/Kubernetes."],"exampleFix":"# before: corrupt/foreign account key blocks startup\nrm -f /var/lib/derper/acme-account.key   # if regenerating is acceptable\nchown -R derper: /var/lib/derper && chmod 700 /var/lib/derper\nsystemctl restart derper","handlingStrategy":"validation","validationCode":"// Pre-flight the cert dir before constructing the IP cert manager.\nfunc checkCertDir(dir string) error {\n    if err := os.MkdirAll(dir, 0700); err != nil { return err }\n    f, err := os.OpenFile(filepath.Join(dir, \".probe\"), os.O_CREATE|os.O_WRONLY, 0600)\n    if err != nil { return fmt.Errorf(\"certdir not writable: %w\", err) }\n    f.Close()\n    os.Remove(filepath.Join(dir, \".probe\"))\n    return nil\n}","typeGuard":null,"tryCatchPattern":"m, err := newIPCertManager(certdir, email, directoryURL, next)\nif err != nil {\n    // unwrapped %w tells you: pem/parse => bad key file, permission => dir perms\n    log.Fatalf(\"ip cert manager: %v\", err)\n}","preventionTips":["Keep the ACME certdir writable by the derper user and 0700.","Persist the certdir across restarts (no ephemeral /tmp for prod).","Do not copy account files from other ACME clients into derper's certdir.","Alert on derper startup failures so a bad account key is caught at deploy time."],"tags":["go","acme","derper","certconfig","filesystem"],"backgroundTag":null,"analyzedSha":"cfe32b8be6a33f8e24fbc369cbfbf7c729d9e042","analyzedAt":"2026-08-15T19:58:31.583Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}