docker/cli · error · invalidParameterErr
unable to get system cert pool
Error message
unable to get system cert pool: %w
What it means
Returned by loadTLSConfig when x509.SystemCertPool() fails while processing a .crt file in the registry TLS directory. SystemCertPool reads the OS trust store; failure (wrapped with invalidParam) means the CLI cannot establish a trusted TLS root set for the registry.
Solutions
- Install the OS CA bundle (e.g. `apt-get install ca-certificates`, `apk add ca-certificates`).
- Ensure $SSL_CERT_FILE / $SSL_CERT_DIR point to existing, readable files/dirs.
- Fix permissions on the system trust store (/etc/ssl/certs).
- Provide the full CA chain via the .crt in certs.d so SystemCertPool fallback is supplemented.
Example fix
# before (alpine, no ca-certificates) docker pull myregistry/app # unable to get system cert pool # after apk add --no-cache ca-certificates docker pull myregistry/app
Defensive patterns
Strategy: try-catch
Validate before calling
// ensure a trust store exists before configuring registry TLS
if _, err := x509.SystemCertPool(); err != nil { installCABundle() } Try / catch
if strings.Contains(err.Error(), "unable to get system cert pool") { installCaCertificates(); retry } Prevention
- Install ca-certificates in minimal/container images.
- Set valid $SSL_CERT_FILE / $SSL_CERT_DIR.
- Keep system trust store readable.
When it happens
Trigger: Configuring a registry with TLS certs (a .crt in /etc/docker/certs.d/<host>/) on a system where the trust store cannot be loaded — missing CA bundle file, unreadable /etc/ssl/certs, minimal/container OS without ca-certificates.
Common situations: Scratch/minimal containers or Alpine without ca-certificates installed; custom $SSL_CERT_FILE pointing at a missing file; permission denied on system CA bundle; unusual platform without a known cert pool.
Related errors
- failed to configure transport
- error pinging v2 registry
- error: username is required
- error: password is required
- conflicting options: cannot specify both --password and…
AI-assisted analysis of docker/cli@4f84911bfe (2026-08-07).
Data as JSON: /api/errors/7570e9b47d7899ef.
Report an issue: GitHub.
Appendix: source
Thrown at internal/registry/registry.go:80
func loadTLSConfig(ctx context.Context, directory string, tlsConfig *tls.Config) error {
fs, err := os.ReadDir(directory)
if err != nil {
if os.IsNotExist(err) {
return nil
}
return invalidParam(err)
}
for _, f := range fs {
if ctx.Err() != nil {
return ctx.Err()
}
switch filepath.Ext(f.Name()) {
case ".crt":
if tlsConfig.RootCAs == nil {
systemPool, err := x509.SystemCertPool()
if err != nil {
return invalidParam(fmt.Errorf("unable to get system cert pool: %w", err))
}
tlsConfig.RootCAs = systemPool
}
fileName := filepath.Join(directory, f.Name())
log.G(ctx).Debugf("crt: %s", fileName)
data, err := os.ReadFile(fileName)
if err != nil {
return err
}
tlsConfig.RootCAs.AppendCertsFromPEM(data)
case ".cert":
certName := f.Name()
keyName := certName[:len(certName)-5] + ".key"
log.G(ctx).Debugf("cert: %s", filepath.Join(directory, certName))
if !hasFile(fs, keyName) {
return invalidParamf("missing key %s for client certificate %s. CA certificates must use the extension .crt", keyName, certName)
}
cert, err := tls.LoadX509KeyPair(filepath.Join(directory, certName), filepath.Join(directory, keyName))View on GitHub (pinned to 4f84911bfe)