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

  1. Point the env var at a specific regular certificate file, e.g. /etc/ssl/certs/ca.crt, not a directory.
  2. If you have multiple CAs, concatenate them into one PEM bundle file.
  3. 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

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 a

View on GitHub (pinned to 3ee70a1026)