apache/superset · error · Error

Found invalid orderby options

Error message

Found invalid orderby options

What it means

Raised by masked_encrypted_extra_validator (superset/databases/schemas.py:260) when the masked_encrypted_extra field is exactly the string "{}". This field round-trips the masked (redacted) form of encrypted_extra in Database API responses; submitting back an empty object means 'no change requested', which Superset rejects as an empty update rather than silently wiping the stored secrets.

Source

Thrown at superset-frontend/packages/superset-ui-core/src/query/extractQueryFields.ts:121

  return {
    columns: removeDuplicates(
      columns.filter(col => col !== ''),
      getColumnLabel,
    ),
    metrics:
      queryMode === QueryMode.Raw
        ? undefined
        : removeDuplicates(metrics, getMetricLabel),
    orderby:
      orderby.length > 0
        ? orderby.map(item => {
            // value can be in the format of `['["col1", true]', '["col2", false]'],
            // where the option strings come directly from `order_by_choices`.
            if (typeof item === 'string') {
              try {
                return JSON.parse(item);
              } catch (error) {
                throw new Error(t('Found invalid orderby options'));
              }
            }
            return item;
          })
        : undefined,
  };
}

View on GitHub (pinned to f4587218dd)

Solutions

  1. Omit masked_encrypted_extra from the PUT payload when you do not intend to change it
  2. Send null instead of "{}" when you want to clear or skip the field
  3. Only send masked_encrypted_extra when replacing secrets, and send real JSON with content

Example fix

# before
body = {**db_response, "masked_encrypted_extra": "{}"}  # 400 Field cannot be empty.

# after
body = {k: v for k, v in db_response.items() if k != "masked_encrypted_extra"}
Defensive patterns

Strategy: validation

Validate before calling

def clean_masked(d: dict) -> dict:
    me = d.get("masked_encrypted_extra")
    if me is not None and (me == "{}" or not me.strip()):
        d.pop("masked_encrypted_extra", None)
    return d

Type guard

const hasMaskedExtra = (b: Record<string, unknown>): boolean =>
  typeof b.masked_encrypted_extra === "string" && b.masked_encrypted_extra.trim() !== "{}" && b.masked_encrypted_extra.trim() !== "";

Prevention

When it happens

Trigger: PUT /api/v1/database/<id> where the client echoes the masked value it previously read, but the database has no encrypted_extra so the masked form is "{}"; or a client that always includes masked_encrypted_extra in the payload, even when empty.

Common situations: Automation that GETs a database, mutates unrelated fields, and PUTs the whole object back including masked_encrypted_extra: "{}". Also forms with a hidden encrypted-extra input defaulting to "{}".

Related errors


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