pathwaycom/pathway · error · ValueError

sslrootcert doesn't point to a file

Error message

sslrootcert doesn't point to a file

What it means

Raised by Pathway's postgres connector (_build_tls_settings) when the sslrootcert setting in postgres_settings points to a directory instead of a regular file. The connector opens the path to validate it before building TLSSettings, and Python raises IsADirectoryError, which is converted to this ValueError.

Source

Thrown at python/pathway/io/postgres/__init__.py:238

        path = "/"
    else:
        path = ""

    owned_settings["replication"] = "database"
    query = "&".join(f"{enc(k)}={enc(v)}" for (k, v) in owned_settings.items())

    return f"postgresql://{userinfo}{hostport}{path}?{query}"


def _build_tls_settings(owned_postgres_settings: dict) -> TLSSettings:
    sslmode = owned_postgres_settings.pop("sslmode", "prefer")

    sslrootcert = owned_postgres_settings.pop("sslrootcert", None)
    if sslrootcert is not None:
        try:
            open(sslrootcert).close()
        except IsADirectoryError as e:
            raise ValueError("sslrootcert doesn't point to a file") from e
        except FileNotFoundError as e:
            raise ValueError("sslrootcert points to a non-existent path") from e
        except OSError as e:
            raise ValueError(f"sslrootcert is not readable: {e}") from e

    return TLSSettings(mode=sslmode, root_cert_path=sslrootcert)


def _construct_replication_settings(
    *,
    mode: Literal["streaming", "static"],
    postgres_settings: dict,
    publication_name: str | None,
    replication_slot_name: str | None,
    snapshot_name: str | None,
):
    # static mode doesn't require replication slots
    if mode == "static":

View on GitHub (pinned to fa2f74a464)

Solutions

  1. Point sslrootcert at a single CA certificate file in PEM format, e.g. /etc/ssl/certs/ca-certificates.crt.
  2. Concatenate the needed CAs into one file (cat bundle/*.pem > ca.pem) and use that path.
  3. If you only wanted sslmode, remove sslrootcert entirely.

Example fix

# before
pw.io.postgres.write(t, parts, "tbl", postgres_settings={"sslmode": "verify-full", "sslrootcert": "/etc/ssl/certs"})
# after
pw.io.postgres.write(t, parts, "tbl", postgres_settings={"sslmode": "verify-full", "sslrootcert": "/etc/ssl/certs/ca-certificates.crt"})
Defensive patterns

Strategy: validation

Validate before calling

import os
p = postgres_settings.get("sslrootcert")
if p is not None:
    assert os.path.isfile(p), f"sslrootcert must be a file, got directory: {p}"

Prevention

When it happens

Trigger: Passing postgres_settings={"sslrootcert": "/etc/ssl/certs"} (a directory) to pw.io.postgres.read/write; passing a path whose trailing slash makes it resolve to a directory.

Common situations: Users point sslrootcert at the system CA bundle directory (as libpq sometimes accepts) instead of a single PEM file like /etc/ssl/cert.pem; copy-pasting sslmode/sslrootcert examples from psql configs.

Related errors


AI-assisted analysis of pathwaycom/pathway@fa2f74a464 (2026-08-15). Data as JSON: /api/errors/7c9158c7d37fbaa7. Report an issue: GitHub.