JuliusBrussee/caveman · error
postgres
Error message
postgres: %s: %w
What it means
Wrapped error from caPEMFromEnvironment: os.Stat failed on the CA file path taken from the CA-file environment variable (missing file, permission, broken symlink). The environment variable name and the stat error are both carried via the format so the cause is inspectable.
Solutions
- Verify the path exists and is readable from the process: `ls -l $POSTGRES_CA_FILE` inside the same container/host.
- Mount the CA certificate file into the container and fix the env var to the absolute mounted path.
- If the CA is provided inline, remove the file env var and use the direct PEM variable instead.
- Check that the user running the process has read permission on the file and its parent directories.
Example fix
// before export POSTGRES_CA_FILE=./certs/ca.crt // relative path, wrong cwd // after export POSTGRES_CA_FILE=/etc/app/certs/ca.crt // absolute path, verified mounted
Defensive patterns
Strategy: validation
Validate before calling
func caFileReadable(path string) error {
if path == "" { return nil }
info, err := os.Stat(path)
if err != nil { return err }
if !info.Mode().IsRegular() { return fmt.Errorf("not a regular file: %s", path) }
f, err := os.Open(path); if err != nil { return err }
f.Close()
return nil
} Try / catch
if _, err := postgresconfig.ParsePoolConfig(dbURL); err != nil {
if errors.Is(err, os.ErrNotExist) {
log.Fatalf("CA file missing: %v", err)
}
return err
} Prevention
- Always use absolute paths for the CA file env var.
- Ensure the CA file is mounted/copied into the container image or volume before startup.
- Verify mounts with a readiness check that stats the file.
When it happens
Trigger: ParsePoolConfig/NewPool called with the CA-file env var set to a path that os.Stat cannot resolve: nonexistent file, typo in path, unreadable parent directory, or dangling symlink.
Common situations: CA file not mounted into the container; wrong mount path in Docker/Kubernetes; relative path used but working directory differs; file deleted after image build.
Understand the failure class
Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.
Related errors
- postgres: read
- postgres: must point to a regular file
- postgres: or is required in production
- postgres: set only or , not both
- load system certificate pool
AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20).
Data as JSON: /api/errors/11d57e48cf9d2603.
Report an issue: GitHub.
Appendix: source
Thrown at shared/platform/postgresconfig/postgresconfig.go:90
fallback.TLSConfig.RootCAs = roots
fallback.TLSConfig.InsecureSkipVerify = false
fallback.TLSConfig.ServerName = fallback.Host
}
return config, nil
}
func caPEMFromEnvironment() (string, error) {
filePath := strings.TrimSpace(os.Getenv(caFileEnvironment))
direct := strings.TrimSpace(os.Getenv(caEnvironment))
if filePath != "" && direct != "" {
return "", fmt.Errorf("postgres: set only %s or %s, not both", caFileEnvironment, caEnvironment)
}
if filePath == "" {
return direct, nil
}
info, err := os.Stat(filePath)
if err != nil {
return "", fmt.Errorf("postgres: %s: %w", caFileEnvironment, err)
}
if !info.Mode().IsRegular() {
return "", fmt.Errorf("postgres: %s must point to a regular file", caFileEnvironment)
}
contents, err := os.ReadFile(filePath)
if err != nil {
return "", fmt.Errorf("postgres: read %s: %w", caFileEnvironment, err)
}
return strings.TrimSpace(string(contents)), nil
}
// NewPool constructs a pool from the hardened configuration.
func NewPool(ctx context.Context, databaseURL string) (*pgxpool.Pool, error) {
config, err := ParsePoolConfig(databaseURL)
if err != nil {
return nil, err
}
return pgxpool.NewWithConfig(ctx, config)View on GitHub (pinned to 3ee70a1026)