File size: 5,558 Bytes
61d29fc
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
"""
Structured error models for API responses.

Provides user-friendly error messages with expandable technical details.
"""
from pydantic import BaseModel, Field
from typing import Optional, Dict, Any


class ErrorDetail(BaseModel):
    """Structured error detail with user-friendly message and technical info."""
    
    message: str = Field(
        ...,
        description="User-friendly error message"
    )
    
    error_type: str = Field(
        ...,
        description="Type of error (e.g., 'data_not_found', 'network_error', 'validation_error')"
    )
    
    technical_details: Optional[str] = Field(
        None,
        description="Technical error details for debugging (expandable in UI)"
    )
    
    suggestions: Optional[list[str]] = Field(
        None,
        description="Helpful suggestions for the user"
    )
    
    metadata: Optional[Dict[str, Any]] = Field(
        None,
        description="Additional context (state, dataset name, etc.)"
    )


def parse_error(exception: Exception, context: Optional[Dict[str, Any]] = None) -> ErrorDetail:
    """
    Parse an exception into a structured ErrorDetail with user-friendly message.
    
    Args:
        exception: The exception to parse
        context: Additional context (state, dataset, etc.)
    
    Returns:
        ErrorDetail with user-friendly message and technical details
    """
    error_str = str(exception)
    context = context or {}
    
    # Parse HuggingFace dataset not found errors
    if "HTTP 404 Not Found" in error_str and "huggingface.co/datasets" in error_str:
        # Extract dataset name from URL
        import re
        match = re.search(r'datasets/([^/]+/[^/]+)/', error_str)
        dataset_name = match.group(1) if match else "unknown"
        
        # Extract state from dataset name or context
        state = context.get('state', 'Unknown')
        data_type = 'bills' if 'bills' in dataset_name else 'data'
        
        return ErrorDetail(
            message=f"No {data_type} data available for {state.upper()}",
            error_type="data_not_found",
            technical_details=f"Dataset '{dataset_name}' not found on HuggingFace.\n\nFull error: {error_str}",
            suggestions=[
                f"Try a different state - we have data for 50+ states",
                f"Check /api/bills/map to see which states have {data_type} data",
                "Contact support if you believe this data should be available"
            ],
            metadata={
                "dataset": dataset_name,
                "state": state,
                "data_type": data_type
            }
        )
    
    # Parse file not found errors (local environment)
    elif "No such file or directory" in error_str or "FileNotFoundError" in error_str:
        state = context.get('state', 'Unknown')
        data_type = context.get('data_type', 'data')
        
        return ErrorDetail(
            message=f"No {data_type} available for {state.upper()}",
            error_type="data_not_found",
            technical_details=error_str,
            suggestions=[
                f"This state may not have {data_type} in our database yet",
                "Try a different state or check which states have data",
                "Data is being continuously added - check back later"
            ],
            metadata={
                "state": state,
                "data_type": data_type
            }
        )
    
    # Parse DuckDB/SQL errors
    elif "DuckDB" in error_str or "SYNTAX ERROR" in error_str or "LINE" in error_str:
        return ErrorDetail(
            message="Database query error - please check your search parameters",
            error_type="query_error",
            technical_details=error_str,
            suggestions=[
                "Try simplifying your search query",
                "Check that all parameters are valid",
                "Contact support if the issue persists"
            ],
            metadata=context
        )
    
    # Parse network/timeout errors
    elif "timeout" in error_str.lower() or "connection" in error_str.lower():
        return ErrorDetail(
            message="Network request timed out - please try again",
            error_type="network_error",
            technical_details=error_str,
            suggestions=[
                "Try again in a few seconds",
                "Check your internet connection",
                "The server may be temporarily busy"
            ],
            metadata=context
        )
    
    # Parse validation errors
    elif "validation" in error_str.lower() or "invalid" in error_str.lower():
        return ErrorDetail(
            message="Invalid request parameters",
            error_type="validation_error",
            technical_details=error_str,
            suggestions=[
                "Check that all required parameters are provided",
                "Verify parameter formats (e.g., state codes should be 2 letters)",
                "See API documentation for valid parameter values"
            ],
            metadata=context
        )
    
    # Generic error fallback
    else:
        return ErrorDetail(
            message="An unexpected error occurred",
            error_type="server_error",
            technical_details=error_str,
            suggestions=[
                "Try again in a few moments",
                "Contact support if the issue persists",
                "Check the technical details for more information"
            ],
            metadata=context
        )