{"record":{"id":"caeced0bad507e38","repo":"docker/cli","slug":"file-contents-must-be-in-pem-format","errorCode":null,"errorMessage":"file contents must be in PEM format","messagePattern":"file contents must be in PEM format","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cli/command/swarm/opts.go","lineNumber":148,"sourceCode":"\n// Type returns the type of this option.\nfunc (*PEMFile) Type() string {\n\treturn \"pem-file\"\n}\n\n// String returns the path to the pem file\nfunc (p *PEMFile) String() string {\n\treturn p.path\n}\n\n// Set parses a root rotation option\nfunc (p *PEMFile) Set(value string) error {\n\tcontents, err := os.ReadFile(value)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif pemBlock, _ := pem.Decode(contents); pemBlock == nil {\n\t\treturn errors.New(\"file contents must be in PEM format\")\n\t}\n\tp.contents, p.path = string(contents), value\n\treturn nil\n}\n\n// Contents returns the contents of the PEM file\nfunc (p *PEMFile) Contents() string {\n\treturn p.contents\n}\n\n// parseExternalCA parses an external CA specification from the command line,\n// such as protocol=cfssl,url=https://example.com.\nfunc parseExternalCA(caSpec string) (*swarm.ExternalCA, error) {\n\tcsvReader := csv.NewReader(strings.NewReader(caSpec))\n\tfields, err := csvReader.Read()\n\tif err != nil {\n\t\treturn nil, err\n\t}","sourceCodeStart":130,"sourceCodeEnd":166,"githubUrl":"https://github.com/docker/cli/blob/4f84911bfe8811e9b028e4b1fee8e7510be79387/cli/command/swarm/opts.go#L130-L166","documentation":"Thrown by PEMFile.Set (cli/command/swarm/opts.go:148) for the `--ca-cert`/`--ca-key` flags during swarm CA rotation. The file at the given path is read and run through pem.Decode; if no PEM block is found (Decode returns nil), the file is not a valid PEM certificate/key and is rejected.","triggerScenarios":"Passing `--ca-cert <path>` (or `--ca-key`) where the file is DER-encoded, plain text, empty, or otherwise not PEM, e.g. `docker swarm ca --rotate --ca-cert cert.der`.","commonSituations":"Wrong encoding (DER instead of PEM); pointing at the wrong file; a key file with no PEM headers; trailing content that breaks the parser; cert generated by a tool that outputs non-PEM by default.","solutions":["Provide a PEM-encoded file (begins with `-----BEGIN CERTIFICATE-----`).","Convert DER to PEM: `openssl x509 -inform der -in cert.der -out cert.pem`.","Verify before passing: `openssl x509 -in cert.pem -noout` (keys: `openssl pkey -in key.pem -noout`)."],"exampleFix":"// before\ndocker swarm ca --rotate --ca-cert cert.der\n\n// after\nopenssl x509 -inform der -in cert.der -out cert.pem\ndocker swarm ca --rotate --ca-cert cert.pem","handlingStrategy":"validation","validationCode":"// Validate PEM before passing to --ca-cert/--ca-key.\nb, err := os.ReadFile(path)\nif err != nil { return err }\nif block, _ := pem.Decode(b); block == nil {\n\treturn fmt.Errorf(\"%s is not PEM-encoded\", path)\n}","typeGuard":"func isPEM(b []byte) bool {\n\tblock, _ := pem.Decode(b)\n\treturn block != nil\n}","tryCatchPattern":null,"preventionTips":["Always generate/export certs in PEM (not DER).","Verify with `openssl x509 -in f -noout` before referencing.","Keep PEM artifacts in a known directory to avoid path mix-ups."],"tags":["docker","swarm","ca","pem","certificates","validation"],"backgroundTag":null,"analyzedSha":"4f84911bfe8811e9b028e4b1fee8e7510be79387","analyzedAt":"2026-08-07T12:15:29.814Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}