hyperledger/fabric · critical
unable to load key at '%s'
Error message
unable to load key at '%s'
What it means
loadDeliverServiceConfig reads the TLS private key file (peer.tls.key.file or the deliver-service-specific key override) and panics with this wrapped error if os.ReadFile fails — typically because the file doesn't exist, isn't readable, or the configured path is empty/relative-wrong. This runs during GlobalConfig initialization, so it crashes the peer at startup.
Source
Thrown at core/deliverservice/config.go:201
c.SecOpts = comm.SecureOptions{
UseTLS: viper.GetBool("peer.tls.enabled"),
RequireClientCert: viper.GetBool("peer.tls.clientAuthRequired"),
}
if c.SecOpts.RequireClientCert {
certFile := config.GetPath("peer.tls.clientCert.file")
if certFile == "" {
certFile = config.GetPath("peer.tls.cert.file")
}
keyFile := config.GetPath("peer.tls.clientKey.file")
if keyFile == "" {
keyFile = config.GetPath("peer.tls.key.file")
}
keyPEM, err := os.ReadFile(keyFile)
if err != nil {
panic(errors.WithMessagef(err, "unable to load key at '%s'", keyFile))
}
c.SecOpts.Key = keyPEM
certPEM, err := os.ReadFile(certFile)
if err != nil {
panic(errors.WithMessagef(err, "unable to load cert at '%s'", certFile))
}
c.SecOpts.Certificate = certPEM
}
overridesMap, err := LoadOverridesMap()
if err != nil {
panic(err)
}
c.OrdererEndpointOverrides = overridesMap
policyKey := "peer.deliveryclient.policy"
policyMissing := !viper.IsSet(policyKey)View on GitHub (pinned to 2736b63f8f)
Solutions
- Verify the key file path in core.yaml (peer.tls.key.file / deliver service key config) and ensure the file exists at that exact path.
- Check file permissions/readability for the user running the peer process.
- In containerized deployments, confirm the secret volume is mounted and CORE_PEER_TLS_KEYFILE points to the mounted path.
- Use absolute paths in config instead of relative ones to avoid CWD dependence.
Example fix
// before (core.yaml)
peer:
tls:
key.file: tls/server.key // relative, file absent
// after
peer:
tls:
key.file: /etc/hyperledger/fabric/tls/server.key // verified existing, readable Defensive patterns
Strategy: validation
Validate before calling
keyPath := viper.GetString("peer.tls.key.file")
if keyPath == "" {
return errors.New("peer.tls.key.file not configured")
}
if fi, err := os.Stat(keyPath); err != nil || fi.IsDir() {
return fmt.Errorf("TLS key file missing: %s", keyPath)
}
if _, err := os.ReadFile(keyPath); err != nil {
return fmt.Errorf("TLS key unreadable: %w", err)
} Try / catch
// This path panics rather than returns, so preflight before peer startup: // run the validation above as a startup preflight; on panic, log the wrapped // cause (errors.Cause) to see the underlying os error (ENOENT vs EACCES).
Prevention
- Preflight-check all TLS files at container/VM startup.
- Use absolute paths for key/cert configuration.
- Verify secret mounts (k8s volumeMounts) before peer launch.
- Keep key files readable by the peer's runtime user (e.g. 0400 owned by that user).
When it happens
Trigger: TLS enabled for the delivery service but the key file path resolves to a nonexistent file, an empty string (config key not set), or a file the peer user cannot read.
Common situations: core.yaml misconfiguration of peer.tls.key.file; missing mounted secret in Kubernetes/Docker; wrong working directory with a relative path; file permissions changed after volume mount; TLS enabled but key file never provisioned.
Related errors
- unable to load cert at '%s'
- invalid external builder configuration, path attribute missi
- external builder at path %s has no name attribute
- peer.address isn't set
- error loading TLS root certificate (%s)
AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04).
Data as JSON: /api/errors/f3dad0f9b72a7c2f.
Report an issue: GitHub.