docker/cli · error
file contents must be in PEM format
Error message
file contents must be in PEM format
What it means
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.
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`).
Example fix
// before docker swarm ca --rotate --ca-cert cert.der // after openssl x509 -inform der -in cert.der -out cert.pem docker swarm ca --rotate --ca-cert cert.pem
Defensive patterns
Strategy: validation
Validate before calling
// Validate PEM before passing to --ca-cert/--ca-key.
b, err := os.ReadFile(path)
if err != nil { return err }
if block, _ := pem.Decode(b); block == nil {
return fmt.Errorf("%s is not PEM-encoded", path)
} Type guard
func isPEM(b []byte) bool {
block, _ := pem.Decode(b)
return block != nil
} Prevention
- 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.
When it happens
Trigger: 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`.
Common situations: 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.
Related errors
- CA cert for external CA must be in PEM format
- other flags may not be combined with --rollback
- duplicate mount target
- no CA information available
- unknown role
AI-assisted analysis of docker/cli@4f84911bfe (2026-08-07).
Data as JSON: /api/errors/caeced0bad507e38.
Report an issue: GitHub.
Appendix: source
Thrown at cli/command/swarm/opts.go:148
// Type returns the type of this option.
func (*PEMFile) Type() string {
return "pem-file"
}
// String returns the path to the pem file
func (p *PEMFile) String() string {
return p.path
}
// Set parses a root rotation option
func (p *PEMFile) Set(value string) error {
contents, err := os.ReadFile(value)
if err != nil {
return err
}
if pemBlock, _ := pem.Decode(contents); pemBlock == nil {
return errors.New("file contents must be in PEM format")
}
p.contents, p.path = string(contents), value
return nil
}
// Contents returns the contents of the PEM file
func (p *PEMFile) Contents() string {
return p.contents
}
// parseExternalCA parses an external CA specification from the command line,
// such as protocol=cfssl,url=https://example.com.
func parseExternalCA(caSpec string) (*swarm.ExternalCA, error) {
csvReader := csv.NewReader(strings.NewReader(caSpec))
fields, err := csvReader.Read()
if err != nil {
return nil, err
}View on GitHub (pinned to 4f84911bfe)