JuliusBrussee/caveman · error
postgres: read
Error message
postgres: read %s: %w
What it means
os.ReadFile on the validated CA file path failed (e.g. permission denied, I/O error, file removed between stat and read). The error is wrapped with 'postgres: read <ENVVAR>:' so the failing variable is identifiable.
Solutions
- Fix file permissions so the process user can read the CA file (chmod/chown or mount with correct mode).
- Ensure the secret/volume is mounted before the application starts.
- Retest the exact read with `sudo -u <appuser> cat "$POSTGRES_CA_FILE"`.
- If the CA is available inline, use the direct PEM env var instead of the file path.
Example fix
// before // k8s secret volume defaultMode: 0400 owned by root, app runs as uid 1000 // after // defaultMode: 0440 with fsGroup: 1000 (or chmod o+r the file)
Defensive patterns
Strategy: validation
Validate before calling
func canReadCA(path string) error {
f, err := os.Open(path)
if err != nil { return err }
defer f.Close()
_, err = f.Read(make([]byte, 1))
return err
} Try / catch
if err := canReadCA(os.Getenv("POSTGRES_CA_FILE")); err != nil {
log.Fatalf("CA file unreadable: %v", err)
} Prevention
- Match secret mount permissions to the app's run-as UID/GID (k8s defaultMode/fsGroup).
- Avoid opening the CA from network filesystems in latency/error-prone setups.
- Read the CA in the entrypoint to fail fast with a clear message.
When it happens
Trigger: ParsePoolConfig/NewPool with the CA-file env var set; file exists and is regular but cannot be read by the process (permissions changed, file deleted in a race, filesystem error).
Common situations: Secret mounted as root-only while the app runs as non-root; NFS/overlay filesystem errors; Kubernetes secret volume not yet mounted at read time.
Understand the failure class
Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.
Related errors
- postgres: must point to a regular file
- postgres
- postgres: CA certificate configured while TLS is disabled
- postgres: production connection includes a plaintext…
- postgres: production DATABASE_URL requires…
AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20).
Data as JSON: /api/errors/8304ddfb2698389d.
Report an issue: GitHub.
Appendix: source
Thrown at shared/platform/postgresconfig/postgresconfig.go:97
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)
}
// NewRuntimePool constructs a pool and proves the connected login is a
// least-privilege member of expectedRole. Runtime services must never connect
// as a superuser, BYPASSRLS role, or owner of a tenant table; this remains true
// for local, on-prem, staging, and production deployments alike.
func NewRuntimePool(ctx context.Context, databaseURL, expectedRole string) (*pgxpool.Pool, error) {View on GitHub (pinned to 3ee70a1026)