{"record":{"id":"dab33e73c235c682","repo":"apache/superset","slug":"unsupported-post-processing-operation-operation","errorCode":null,"errorMessage":"Unsupported post processing operation: %(operation)s","messagePattern":"Unsupported post processing operation: (.+?)","errorType":"validation","errorClass":"InvalidPostProcessingError","httpStatus":400,"severity":"error","filePath":"superset/common/query_object.py","lineNumber":548,"sourceCode":"        \"\"\"\n        Perform post processing operations on DataFrame.\n\n        :param df: DataFrame returned from database model.\n        :return: new DataFrame to which all post processing operations have been\n                 applied\n        :raises QueryObjectValidationError: If the post processing operation\n                 is incorrect\n        \"\"\"\n        logger.debug(\"post_processing: \\n %s\", pformat(self.post_processing))\n        with event_logger.log_context(f\"{self.__class__.__name__}.post_processing\"):\n            for post_process in self.post_processing:\n                operation = post_process.get(\"operation\")\n                if not operation:\n                    raise InvalidPostProcessingError(\n                        _(\"`operation` property of post processing object undefined\")\n                    )\n                if not hasattr(pandas_postprocessing, operation):\n                    raise InvalidPostProcessingError(\n                        _(\n                            \"Unsupported post processing operation: %(operation)s\",\n                            type=operation,\n                        )\n                    )\n                options = post_process.get(\"options\", {})\n                df = getattr(pandas_postprocessing, operation)(df, **options)\n            return df\n","sourceCodeStart":530,"sourceCodeEnd":557,"githubUrl":"https://github.com/apache/superset/blob/f4587218dd19d046c3e4d00063e7d27f8a2ed354/superset/common/query_object.py#L530-L557","documentation":"InvalidPostProcessingError raised in QueryObject.get_post_processing_df (query_object.py:548) when the operation string in a post_processing entry does not match any attribute of superset.common.utils.pandas_postprocessing. Superset dispatches post-processing via getattr(pandas_postprocessing, operation), so unknown operation names (typos, renamed functions, plugin-specific ops) are rejected before execution.","triggerScenarios":"A post_processing entry whose operation is e.g. \"pivt\", \"timeseries\", or any name not defined in pandas_postprocessing.py. Happens after Superset upgrades that rename/remove post-processing ops, or when a payload was written against a fork/plugin that supports extra operations.","commonSituations":"Typos in hand-written API payloads; chart definitions persisted from an older Superset version referencing an operation that was renamed (e.g. legacy 'concat' variants); custom forks adding operations that upstream rejects.","solutions":["Check superset/common/utils/pandas_postprocessing.py (or dir(pandas_postprocessing)) in your Superset version for the exact allowed operation names and correct the payload.","Fix typos: common valid operations include pivot, aggregate, rolling, diff, rank, cum, contribution, geographical, boxplot.","After a Superset upgrade, re-open and re-save affected charts in Explore so post_processing is normalized to the current schema."],"exampleFix":"// before\n\"post_processing\": [\n  { \"operation\": \"pivt\", \"options\": { ... } }\n]\n\n// after\n\"post_processing\": [\n  { \"operation\": \"pivot\", \"options\": { ... } }\n]","handlingStrategy":"validation","validationCode":"from superset.common.utils import pandas_postprocessing\n\nALLOWED = {\n    name for name in dir(pandas_postprocessing)\n    if not name.startswith(\"_\") and callable(getattr(pandas_postprocessing, name))\n}\n\ndef validate_operations(steps: list[dict]) -> None:\n    for step in steps or []:\n        if step.get(\"operation\") not in ALLOWED:\n            raise ValueError(f\"unsupported operation: {step.get('operation')!r}; allowed: {sorted(ALLOWED)}\")","typeGuard":"def is_supported_operation(step: dict) -> bool:\n    from superset.common.utils import pandas_postprocessing\n    op = step.get(\"operation\")\n    return isinstance(op, str) and hasattr(pandas_postprocessing, op)","tryCatchPattern":"from superset.exceptions import InvalidPostProcessingError\n\ntry:\n    df = query_object.get_post_processing_df(df)\nexcept InvalidPostProcessingError as ex:\n    if \"Unsupported post processing operation\" in str(ex):\n        # drop or map the unknown op, then retry\n        query_object.post_processing = [s for s in query_object.post_processing if is_supported_operation(s)]\n        df = query_object.get_post_processing_df(df)\n    else:\n        raise","preventionTips":["Check allowed operation names against your pinned Superset version's pandas_postprocessing module.","Treat operation as an enum in client code, not free text.","After Superset upgrades, grep saved charts for removed/renamed post-processing operations."],"tags":["post-processing","pandas","dispatch","superset"],"backgroundTag":null,"analyzedSha":"f4587218dd19d046c3e4d00063e7d27f8a2ed354","analyzedAt":"2026-08-14T22:39:27.425Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}