apache/seatunnel · error · IllegalStateException

Python source is disabled by the server-side security…

Error message

Python source is disabled by the server-side security policy. Set -D{}=true and configure -D{} with absolute interpreter paths on every worker node.

What it means

PythonSourceExecutionPolicy.ensureEnabled throws this IllegalStateException when the system property PYTHON_SOURCE_ENABLED_PROPERTY is not set to true. The Python source is opt-in and disabled by default as a server-side security policy; enabling also requires configuring the allowed-executables property with absolute interpreter paths on every worker node.

Solutions

  1. Start every node's JVM with -Dpython.source.enabled=true (or the documented property name).
  2. Also set -Dpython.allowed.executables=/abs/path/python3 with absolute interpreter paths on every worker.
  3. Put both properties in the server JVM options file so restarts keep them (e.g. JVM options in seatunnel.sh/env config).
  4. If you do not need the Python source, remove it from the job instead of enabling it cluster-wide.
  5. Verify with a small test job after restart; the properties are read at runtime via System.getProperty, so no rebuild is needed.

Example fix

// before
./bin/seatunnel-cluster.sh  # python source disabled
// after
JAVA_OPTS="-Dpython.source.enabled=true -Dpython.allowed.executables=/usr/bin/python3" \
  ./bin/seatunnel-cluster.sh
Defensive patterns

Strategy: validation

Validate before calling

// Java: preflight before submitting a Python-source job
boolean enabled = Boolean.parseBoolean(
    System.getProperty("python.source.enabled", "false"));
if (!enabled) {
    throw new IllegalStateException(
        "Python source disabled: start workers with -Dpython.source.enabled=true "
        + "and -Dpython.allowed.executables=<abs paths>");
}

Try / catch

try { source.prepare(...); } catch (IllegalStateException e) { if (e.getMessage().contains("disabled by the server-side security policy")) { LOG.error("Enable via JVM properties on every worker", e); } }

Prevention

When it happens

Trigger: Submitting a job using the Python source when the cluster JVMs were started without -Dpython.source.enabled=true; ensureEnabled runs as part of resolveExecutable before any subprocess launch.

Common situations: Fresh cluster deployment where the security properties were never added to JVM options; enabling on the client but forgetting worker nodes; properties set in one config file (e.g. seatunnel-env) but not in the actual JVM start script.

Related errors


AI-assisted analysis of apache/seatunnel@cf67b549a7 (2026-09-10). Data as JSON: /api/errors/1f086561f2928770. Report an issue: GitHub.

Appendix: source

Thrown at seatunnel-connectors-v2/connector-python/src/main/java/org/apache/seatunnel/connectors/seatunnel/python/source/PythonSourceExecutionPolicy.java:65

            if (sameExecutablePath(resolvedExecutable, allowedExecutable)) {
                return resolvedExecutable;
            }
        }
        throw new IllegalStateException(
                "Python source executable "
                        + resolvedExecutable
                        + " is not listed in server property "
                        + PYTHON_ALLOWED_EXECUTABLES_PROPERTY
                        + "="
                        + allowedExecutables);
    }

    private static void ensureEnabled() {
        if (Boolean.parseBoolean(
                System.getProperty(PYTHON_SOURCE_ENABLED_PROPERTY, Boolean.FALSE.toString()))) {
            return;
        }
        throw new IllegalStateException(
                "Python source is disabled by the server-side security policy. Set -D"
                        + PYTHON_SOURCE_ENABLED_PROPERTY
                        + "=true and configure -D"
                        + PYTHON_ALLOWED_EXECUTABLES_PROPERTY
                        + " with absolute interpreter paths on every worker node.");
    }

    private static List<Path> parseAllowedExecutables() {
        String rawAllowlist = System.getProperty(PYTHON_ALLOWED_EXECUTABLES_PROPERTY, "");
        if (rawAllowlist.trim().isEmpty()) {
            throw new IllegalStateException(
                    "Server property "
                            + PYTHON_ALLOWED_EXECUTABLES_PROPERTY
                            + " must contain at least one absolute executable path");
        }
        Set<Path> allowedExecutables = new LinkedHashSet<>();
        for (String rawEntry : rawAllowlist.split(",")) {
            String entry = rawEntry.trim();

View on GitHub (pinned to cf67b549a7)