zylon-ai/private-gpt · warning · ValueError

Output is not a pd.DataFrame

Error message

Output is not a pd.DataFrame

What it means

PandasAIOutput.get_dataframe() is a narrowing accessor: it returns self.value as a pd.DataFrame only when isinstance(self.value, pd.DataFrame) holds; otherwise ValueError. The output value's type depends on what the generated code last-expression/last-produced value was, so this fires when the analysis returned something other than a frame (a string, number, or chart).

Source

Thrown at private_gpt/components/tabular/pandasai_service.py:146

    def is_number(self) -> bool:
        """Check if the value is a number."""
        # Try to cast to int, float, or complex
        return isinstance(self.value, int | float | complex) and not isinstance(
            self.value, bool
        )

    def is_dataframe(self) -> bool:
        """Check if the value is a pandas DataFrame."""
        return isinstance(self.value, pd.DataFrame)

    def is_chart(self) -> bool:
        """Check if the response is a chart."""
        return isinstance(self.response, ChartResponse)

    def get_dataframe(self) -> pd.DataFrame:
        """Get the value as a DataFrame, or raise an error."""
        if not self.is_dataframe():
            raise ValueError("Output is not a pd.DataFrame")
        return cast(pd.DataFrame, self.value)

    def get_chart(self) -> Image:
        """Get the chart as an Image, or raise an error."""
        if not self.is_chart():
            raise ValueError("Output is not a chart")
        img = cast(ChartResponse, self.response)._get_image()
        return cast(Image, img)

    def _determine_response_type(self) -> str | None:
        """Determine the response type for dispatching."""
        type_checks = [
            ("dataframe", self.is_dataframe),
            ("chart", self.is_chart),
            ("string", self.is_string),
            ("number", self.is_number),
        ]

View on GitHub (pinned to 4a030776a3)

Solutions

  1. Branch on output.is_dataframe() (or _determine_response_type) before calling get_dataframe().
  2. Use str(output) or the handlers dict which handles all types gracefully.
  3. If a frame is required, re-prompt the analysis with an explicit instruction to return a DataFrame.

Example fix

# before
df = output.get_dataframe()  # ValueError when result is a chart

# after
if output.is_dataframe():
    df = output.get_dataframe()
else:
    df = None  # or handle chart/string/number branches
Defensive patterns

Strategy: type-guard

Type guard

def as_dataframe(output):
    return output.get_dataframe() if output.is_dataframe() else None

Prevention

When it happens

Trigger: Calling get_dataframe() after a chat run whose result is a chart (ChartResponse), a string, or a number; the generated code's final value is a print-out or scalar rather than a DataFrame; response-type dispatch said 'chart' or 'string'.

Common situations: Caller assumes tabular output for every query, but the user's prompt asked for a plot or a single number; mixed workloads where the same handler must branch on result type.

Related errors


AI-assisted analysis of zylon-ai/private-gpt@4a030776a3 (2026-08-15). Data as JSON: /api/errors/4688604b5b485119. Report an issue: GitHub.