apache/superset · error · Error

Unsupported whisker type

Error message

Unsupported whisker type: ${whiskerOptions}

What it means

Raised by encrypted_extra_validator in superset/databases/schemas.py when the encrypted_extra field submitted to the Database REST API is non-empty but fails json.loads. Superset stores encrypted_extra (driver-specific secrets like credentials_params) as a JSON string, so any non-JSON payload is rejected with a marshmallow ValidationError before the DAO layer runs. The API turns this into an HTTP 400 with the JSONDecodeError detail appended to the message.

Solutions

  1. Serialize the value with json.dumps() (or JSON.stringify on the frontend) before sending it as encrypted_extra
  2. Validate the string with json.loads() locally first; the exception message includes the exact JSONDecodeError position
  3. If you intended no encrypted extra, send null or omit the field entirely rather than a malformed string

Example fix

# before
payload = {"encrypted_extra": str({"credentials_params": {"user": "bob"}})}  # Python repr -> 400

# after
import json
payload = {"encrypted_extra": json.dumps({"credentials_params": {"user": "bob"}})}
Defensive patterns

Strategy: validation

Validate before calling

import json

def valid_json_string(v: str | None) -> bool:
    if v is None or v == "":
        return True
    try:
        json.loads(v)
        return True
    except json.JSONDecodeError:
        return False

assert valid_json_string(payload.get("encrypted_extra")), "encrypted_extra must be valid JSON"

Type guard

def isJsonString(v: unknown): boolean {
  if (v == null || v === "") return true;
  try { JSON.parse(v as string); return true; } catch { return false; }
}

Try / catch

resp = requests.post(url, json=payload)
if resp.status_code == 400 and "cannot be decoded by JSON" in resp.text:
    raise ValueError(f"encrypted_extra not valid JSON: {resp.text}") from None

Prevention

When it happens

Trigger: POST /api/v1/database/ or PUT /api/v1/database/<id> with a body whose encrypted_extra is a bare string, unquoted key, trailing comma, or Python dict literal (single quotes) instead of valid JSON; also passing an already-encrypted binary blob or an empty string with stray whitespace characters.

Common situations: Scripts that build encrypted_extra via Python repr() instead of json.dumps(), pasting YAML/INI fragments into the field, or frontend forms serializing the object lazily. Also hit after upgrades when the encrypted_extra payload format was restructured and old tooling sends the previous shape.

Related errors


AI-assisted analysis of apache/superset@f4587218dd (2026-08-14). Data as JSON: /api/errors/43ae6964b0280bd2. Report an issue: GitHub.

Appendix: source

Thrown at superset-frontend/packages/superset-ui-chart-controls/src/operators/boxplotOperator.ts:52

  const { groupby, whiskerOptions } = formData;

  if (whiskerOptions) {
    let whiskerType: BoxPlotQueryObjectWhiskerType;
    let percentiles: [number, number] | undefined;
    const percentileMatch = PERCENTILE_REGEX.exec(whiskerOptions as string);

    if (whiskerOptions === 'Tukey' || !whiskerOptions) {
      whiskerType = 'tukey';
    } else if (whiskerOptions === 'Min/max (no outliers)') {
      whiskerType = 'min/max';
    } else if (percentileMatch) {
      whiskerType = 'percentile';
      percentiles = [
        parseInt(percentileMatch[1], 10),
        parseInt(percentileMatch[2], 10),
      ];
    } else {
      throw new Error(`Unsupported whisker type: ${whiskerOptions}`);
    }

    return {
      operation: 'boxplot',
      options: {
        whisker_type: whiskerType,
        percentiles,
        groupby: ensureIsArray(groupby).map(getColumnLabel),
        metrics: ensureIsArray(queryObject.metrics).map(getMetricLabel),
      },
    };
  }
  return undefined;
};

View on GitHub (pinned to f4587218dd)