JuliusBrussee/caveman · error
postgres: must point to a regular file
Error message
postgres: %s must point to a regular file
What it means
Error from caPEMFromEnvironment: the path set in the CA-file environment variable exists but is not a regular file (directory, device, fifo). Only a readable regular file can be loaded as a PEM CA bundle, so other file modes are rejected.
Solutions
- Point the env var at a specific regular certificate file, e.g. /etc/ssl/certs/ca.crt, not a directory.
- If you have multiple CAs, concatenate them into one PEM bundle file.
- Verify with `test -f "$POSTGRES_CA_FILE"` before starting the service.
Example fix
// before export POSTGRES_CA_FILE=/etc/ssl/certs // a directory // after export POSTGRES_CA_FILE=/etc/ssl/certs/ca-certificates.crt
Defensive patterns
Strategy: validation
Validate before calling
if info, err := os.Stat(os.Getenv("POSTGRES_CA_FILE")); err == nil && !info.Mode().IsRegular() {
return errors.New("POSTGRES_CA_FILE must be a regular file, not a directory")
} Try / catch
if err := postgresconfig.ValidateTenantSchema(ctx, pool); err != nil {
if strings.Contains(err.Error(), "must point to a regular file") { /* fix path config */ }
} Prevention
- Point CA vars at specific .crt/.pem files, never directories.
- Concatenate multiple CAs into one bundle file.
- Add `test -f "$POSTGRES_CA_FILE"` to entrypoint scripts.
When it happens
Trigger: The CA-file env var points at a directory (common typo: trailing path to a folder of certs) or at a non-regular filesystem object.
Common situations: Pointing the variable at /etc/ssl/certs (a directory) instead of a specific .crt file; using a named pipe set up by an init container; bind-mounting a directory where a file was expected.
Related errors
AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20).
Data as JSON: /api/errors/e4d46530a06e1ab3.
Report an issue: GitHub.
Appendix: source
Thrown at shared/platform/postgresconfig/postgresconfig.go:93
}
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)
}
// NewRuntimePool constructs a pool and proves the connected login is aView on GitHub (pinned to 3ee70a1026)