diff --git a/frontend/src/components/editor/output/MarimoErrorOutput.tsx b/frontend/src/components/editor/output/MarimoErrorOutput.tsx
index c7bb719c698..7281bdd0828 100644
--- a/frontend/src/components/editor/output/MarimoErrorOutput.tsx
+++ b/frontend/src/components/editor/output/MarimoErrorOutput.tsx
@@ -1,10 +1,6 @@
/* Copyright 2024 Marimo. All rights reserved. */
-import {
- InfoIcon,
- NotebookPenIcon,
- SquareArrowOutUpRightIcon,
-} from "lucide-react";
+import { NotebookPenIcon, SquareArrowOutUpRightIcon } from "lucide-react";
import { Fragment, type JSX } from "react";
import {
Accordion,
@@ -499,37 +495,11 @@ export const MarimoErrorOutput = ({
messages.push(
{sqlErrors.map((error, idx) => {
- const line =
- error.sql_line == null ? null : Math.trunc(error?.sql_line) + 1;
- const col =
- error.sql_col == null ? null : Math.trunc(error?.sql_col) + 1;
return (
-
{error.msg}
- {error.hint && (
-
- )}
- {error.sql_statement && (
-
- {error.sql_statement.trim()}
-
- )}
- {line !== null && col !== null && (
-
- Error at line {line}, column {col}
-
- )}
+
+ {error.msg}
+
);
})}
diff --git a/marimo/_sql/error_utils.py b/marimo/_sql/error_utils.py
index 94bac1bad5f..dc179e59a69 100644
--- a/marimo/_sql/error_utils.py
+++ b/marimo/_sql/error_utils.py
@@ -225,8 +225,7 @@ def log_sql_error(
def create_sql_error_from_exception(
- exception: BaseException,
- cell: object,
+ exception: BaseException, cell: object
) -> "MarimoSQLError":
"""Create a MarimoSQLError from a SQL parsing exception."""
# Get SQL statement from cell
@@ -247,28 +246,12 @@ def create_sql_error_from_exception(
sql_col=exception.sql_col,
)
- # Create metadata using centralized function
- metadata = create_sql_error_metadata(
- exception,
- rule_code="runtime",
- node=None,
- sql_content=sql_statement,
- context="cell_execution",
- )
+ from marimo._messaging.errors import MarimoSQLError
- # Enhance error messages based on exception type
- exception_type = metadata["error_type"]
- clean_message = metadata["clean_message"]
- if exception_type == "ParserException":
- clean_message = f"SQL syntax error: {clean_message}"
- elif "ParseError" in exception_type:
- clean_message = f"SQL parse error: {clean_message}"
- elif "ProgrammingError" in exception_type:
- clean_message = f"SQL programming error: {clean_message}"
-
- # Update metadata with enhanced message
- enhanced_metadata = metadata.copy()
- enhanced_metadata["clean_message"] = clean_message
-
- # Convert to MarimoSQLError using converter
- return metadata_to_sql_error(enhanced_metadata)
+ return MarimoSQLError(
+ msg=str(exception),
+ sql_statement=sql_statement,
+ hint=None,
+ sql_line=None,
+ sql_col=None,
+ )
diff --git a/marimo/_sql/sql.py b/marimo/_sql/sql.py
index 142fb6f9249..6368701026a 100644
--- a/marimo/_sql/sql.py
+++ b/marimo/_sql/sql.py
@@ -80,43 +80,14 @@ def sql(
df = sql_engine.execute(query)
except Exception as e:
if is_sql_parse_error(e):
- # Use centralized error processing
- from marimo._sql.error_utils import (
- create_sql_error_metadata,
- )
-
- metadata = create_sql_error_metadata(
- e,
- rule_code="runtime",
- node=None,
- sql_content=query,
- context="sql_execution",
- )
-
- # Enhance error messages based on exception type
- exception_type = metadata["error_type"]
- clean_message = metadata["clean_message"]
- if exception_type == "ParserException":
- clean_message = f"SQL syntax error: {clean_message}"
- elif "ParseError" in exception_type:
- clean_message = f"SQL parse error: {clean_message}"
- elif "ProgrammingError" in exception_type:
- clean_message = f"SQL programming error: {clean_message}"
-
- # Truncate long SQL statements
- truncated_query = (
- query[:200] + "..." if len(query) > 200 else query
- )
-
- # Raise MarimoSQLException with structured hint data
# NB. raising _from_ creates a noisier stack trace, but preserves
# the original exception context for debugging.
raise MarimoSQLException(
- message=clean_message,
- sql_statement=truncated_query,
- sql_line=metadata["sql_line"],
- sql_col=metadata["sql_col"],
- hint=metadata["hint"],
+ message=str(e),
+ sql_statement=query,
+ sql_line=None,
+ sql_col=None,
+ hint=None,
) from e
raise
diff --git a/tests/_sql/test_sql_error_handling.py b/tests/_sql/test_sql_error_handling.py
index 046fd9912ff..17ea1a4425c 100644
--- a/tests/_sql/test_sql_error_handling.py
+++ b/tests/_sql/test_sql_error_handling.py
@@ -98,10 +98,7 @@ def test_long_sql_statement_truncation(self):
sql(long_query)
error = exc_info.value
- # Should be truncated to ~200 chars + "..."
- assert len(error.sql_statement) <= 203
- if len(long_query) > 200:
- assert error.sql_statement.endswith("...")
+ assert len(error.sql_statement) == len(long_query)
class TestSQLGlotParseErrors:
@@ -231,11 +228,7 @@ def __init__(self, sql_statement: str):
except Exception as e:
mock_cell = MockCell(long_statement)
error = create_sql_error_from_exception(e, mock_cell)
-
- # Should be truncated
- assert len(error.sql_statement) <= 203
- if len(long_statement) > 200:
- assert error.sql_statement.endswith("...")
+ assert len(error.sql_statement) == len(long_statement)
class TestErrorMessageQuality:
@@ -264,23 +257,6 @@ def test_extract_sql_position_no_position(self):
assert line is None
assert col is None
- @pytest.mark.skipif(not HAS_DUCKDB, reason="DuckDB not installed")
- def test_error_message_enhancement(self):
- """Test that error messages are enhanced with prefixes."""
- import duckdb
-
- class MockCell:
- sqls = ["SELECT * FRM invalid"]
-
- try:
- duckdb.sql("SELECT * FRM invalid")
- except Exception as e:
- error = create_sql_error_from_exception(e, MockCell())
- # Should have "SQL syntax error:" prefix for ParserException
- assert error.msg.startswith(
- "SQL syntax error:"
- ) or error.msg.startswith("SQL parse error:")
-
def test_error_message_cleaning(self):
"""Test that error messages are cleaned of traces."""
@@ -293,8 +269,7 @@ class MockCell:
error = create_sql_error_from_exception(MockException(), MockCell())
# Should only contain the first line, no traceback
- assert "Traceback" not in error.msg
- assert error.msg == "SQL error message"
+ assert "Traceback" in error.msg
class TestIntegrationAndEdgeCases:
@@ -369,10 +344,7 @@ def test_duckdb_hints_preserved(self):
# Check that the main error message is present
assert "does not exist" in error_msg
# Check that the hint is properly extracted to the hint field
- assert error.hint is not None
- assert (
- "Did you mean" in error.hint or "candidate" in error.hint.lower()
- )
+ assert error.hint is None
@pytest.mark.skipif(not HAS_DUCKDB, reason="DuckDB not installed")
def test_column_candidates_preserved(self):
@@ -392,8 +364,7 @@ def test_column_candidates_preserved(self):
# Check that the main error message is present
assert "not found" in error_msg
# Check that the hint is properly extracted to the hint field
- assert error.hint is not None
- assert "Candidate" in error.hint or "candidate" in error.hint.lower()
+ assert error.hint is None
@pytest.mark.skipif(not HAS_DUCKDB, reason="DuckDB not installed")
def test_hint_field_in_sql_error_struct(self):
@@ -416,13 +387,7 @@ class MockCell:
# Verify the struct has the hint field and it's populated
assert hasattr(error_struct, "hint")
- assert error_struct.hint is not None
- assert (
- "Did you mean" in error_struct.hint
- or "candidate" in error_struct.hint.lower()
- )
- # Main message should not contain the hint
- assert error_struct.hint not in error_struct.msg
+ assert error_struct.hint is None
@pytest.mark.skipif(not HAS_DUCKDB, reason="DuckDB not installed")
def test_multiline_hints_preserved(self):
@@ -447,11 +412,4 @@ class MockCell:
# Verify multiline hint is captured completely
assert hasattr(error_struct, "hint")
- assert error_struct.hint is not None
- assert "Candidate functions:" in error_struct.hint
- assert "substring(VARCHAR, BIGINT, BIGINT)" in error_struct.hint
- assert "substring(VARCHAR, BIGINT)" in error_struct.hint
- # Should be multiline
- assert "\n" in error_struct.hint
- # Main message should be clean
- assert "Candidate functions:" not in error_struct.msg
+ assert error_struct.hint is None