apache/druid · critical · ISE

set to 'false', but has been removed, see for details for…

Error message

%s set to 'false', but has been removed, see %s for details for how to migrate to SQL compliant behavior

What it means

The three-value-logic toggle druid.sql.expressionProcessor/three-value-logic config has been removed; Druid now always uses three-valued logic when SQL-compliant null handling is on. StartupInjectorBuilder.validate() throws this ISE at startup if the property is set to 'false' to prevent silently reverting to legacy non-3VL semantics.

Solutions

  1. Remove the property or set it to 'true' in runtime properties
  2. Migrate queries per the linked ANSI SQL null migration doc to get expected results under three-valued logic
  3. Audit dashboards/scheduled queries that relied on legacy boolean NULL semantics and update comparisons (e.g. use IS NOT DISTINCT FROM or explicit NULL checks)

Example fix

// before
<removed-3vl-property>=false
// after
# property removed (3VL always enabled)
Defensive patterns

Strategy: validation

Validate before calling

String v = props.getProperty("<three-value-logic-property>");
if ("false".equalsIgnoreCase(v)) throw new IllegalStateException("3VL toggle removed; must not be 'false'");

Try / catch

try { injector = StartupInjectorBuilder.build(); } catch (ISE e) { if (e.getMessage().contains("set to 'false', but has been removed")) log.error("Remove the legacy 3VL flag; see migration doc"); throw e; }

Prevention

When it happens

Trigger: validate() computes no3vl = !Boolean.parseBoolean(properties.getProperty(THREE_VALUE_LOGIC_CONFIG_STRING, "true")); the property being explicitly 'false' triggers the throw before the injector is built.

Common situations: Clusters upgraded from legacy versions where 3VL was opt-in; ops teams disabling 3VL to reproduce old query results; stale config files carried across upgrades.

Related errors


AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07). Data as JSON: /api/errors/bd2db295dd99f598. Report an issue: GitHub.

Appendix: source

Thrown at processing/src/main/java/org/apache/druid/guice/StartupInjectorBuilder.java:154

    {
      final boolean defaultValueMode = Boolean.parseBoolean(
          properties.getProperty(NULL_HANDLING_CONFIG_STRING, "false")
      );
      if (defaultValueMode) {
        final String docsLink = StringUtils.format("https://druid.apache.org/docs/%s/release-info/migr-ansi-sql-null", getVersionString());
        throw new ISE(
            "%s set to 'true', but has been removed, see %s for details for how to migrate to SQL compliant behavior",
            NULL_HANDLING_CONFIG_STRING,
            docsLink
        );
      }

      final boolean no3vl = !Boolean.parseBoolean(
          properties.getProperty(THREE_VALUE_LOGIC_CONFIG_STRING, "true")
      );
      if (no3vl) {
        final String docsLink = StringUtils.format("https://druid.apache.org/docs/%s/release-info/migr-ansi-sql-null", getVersionString());
        throw new ISE(
            "%s set to 'false', but has been removed, see %s for details for how to migrate to SQL compliant behavior",
            THREE_VALUE_LOGIC_CONFIG_STRING,
            docsLink
        );
      }

      final boolean nonStrictExpressions = !Boolean.parseBoolean(
          properties.getProperty(ExpressionProcessingConfig.NULL_HANDLING_LEGACY_LOGICAL_OPS_STRING, "true")
      );
      if (nonStrictExpressions) {
        final String docsLink = StringUtils.format("https://druid.apache.org/docs/%s/release-info/migr-ansi-sql-null", getVersionString());
        throw new ISE(
            "%s set to 'false', but has been removed, see %s for details for how to migrate to SQL compliant behavior",
            ExpressionProcessingConfig.NULL_HANDLING_LEGACY_LOGICAL_OPS_STRING,
            docsLink
        );
      }

View on GitHub (pinned to 9b90983fd2)