@@ -161,10 +161,30 @@ def _normalize_enodia_error(error_message: str) -> str:
161161 return error_message
162162
163163
164+ def extract_error_payload (error_message : str ) -> dict | None :
165+ """Find a structured error payload in direct or gRPC-wrapped Flight text."""
166+ normalized_message = _normalize_enodia_error (error_message )
167+ messages = (error_message ,) if normalized_message == error_message else (error_message , normalized_message )
168+
169+ for message in messages :
170+ for delimiter in re .finditer (r"::" , message ):
171+ payload_text = message [delimiter .end () :]
172+ for brace in re .finditer (r"\{" , payload_text ):
173+ json_part = _extract_json_object (payload_text [brace .start () :])
174+ try :
175+ payload = json .loads (json_part )
176+ except json .JSONDecodeError :
177+ continue
178+ if isinstance (payload , dict ):
179+ return payload
180+
181+ return None
182+
183+
164184_UNKNOWN_ERROR = "Unknown error"
165185
166186
167- def parse_dataconnect_error (ex : Exception ) -> TransportError :
187+ def parse_dataconnect_error (ex : Exception , trace_id : str | None = None ) -> TransportError :
168188 """Parse a raw exception into a typed ``TransportError``.
169189
170190 Extracts a structured ``PREFIX::JSON`` payload from the exception message,
@@ -175,85 +195,88 @@ def parse_dataconnect_error(ex: Exception) -> TransportError:
175195 the message cannot be parsed or does not match the expected format.
176196 """
177197 try :
198+ if isinstance (ex , TransportError ):
199+ if ex .trace_id is None :
200+ ex .trace_id = trace_id
201+ return ex
202+
178203 error_message = str (ex )
179204
180- # Normalize enodia authentication errors into PREFIX::JSON format
181- error_message = _normalize_enodia_error (error_message )
182-
183- if "::" in error_message :
184- delimiter_pos = error_message .index ("::" )
185- json_part_raw = error_message [delimiter_pos + 2 :]
186-
187- if json_part_raw :
188- json_part = _extract_json_object (json_part_raw )
189-
190- error_data : dict = json .loads (json_part )
191-
192- parsed_details : list [ErrorDetail ] | None = None
193- raw_details = error_data .get ("details" )
194- if isinstance (raw_details , list ):
195- standard_keys = {"field" , "message" , "expected" }
196- parsed_details = [
197- ErrorDetail (
198- field = item .get ("field" ),
199- message = item .get ("message" ),
200- expected = item .get ("expected" ),
201- extra = {k : v for k , v in item .items () if k not in standard_keys },
202- )
203- for item in raw_details
204- if isinstance (item , dict )
205- ]
206-
207- error_code = error_data .get ("error_code" , "SDK_ERROR" )
208-
209- if error_code .startswith ("AUTH_" ):
210- return TransportAuthenticationError (
211- error_code = error_code ,
212- message = error_data .get ("message" ) or _UNKNOWN_ERROR ,
213- timestamp = error_data .get ("timestamp" ),
214- details = parsed_details ,
205+ error_data = extract_error_payload (error_message )
206+ if error_data is not None :
207+ parsed_details : list [ErrorDetail ] | None = None
208+ raw_details = error_data .get ("details" )
209+ if isinstance (raw_details , list ):
210+ standard_keys = {"field" , "message" , "expected" }
211+ parsed_details = [
212+ ErrorDetail (
213+ field = item .get ("field" ),
214+ message = item .get ("message" ),
215+ expected = item .get ("expected" ),
216+ extra = {k : v for k , v in item .items () if k not in standard_keys },
215217 )
218+ for item in raw_details
219+ if isinstance (item , dict )
220+ ]
216221
217- if error_code .startswith ("AUTHZ_" ):
218- return TransportAuthorizationError (
219- error_code = error_code ,
220- message = error_data .get ("message" ) or _UNKNOWN_ERROR ,
221- timestamp = error_data .get ("timestamp" ),
222- details = parsed_details ,
223- )
222+ error_code = error_data .get ("error_code" , "SDK_ERROR" )
223+ payload_trace_id = error_data .get ("trace_id" )
224+ parsed_trace_id = payload_trace_id if isinstance (payload_trace_id , str ) and payload_trace_id else trace_id
224225
225- if error_code .startswith ("VAL_" ):
226- return TransportValidationError (
227- error_code = error_code ,
228- message = error_data .get ("message" ) or _UNKNOWN_ERROR ,
229- timestamp = error_data .get ("timestamp" ),
230- details = parsed_details ,
231- )
226+ if error_code .startswith ("AUTH_" ):
227+ return TransportAuthenticationError (
228+ error_code = error_code ,
229+ message = error_data .get ("message" ) or _UNKNOWN_ERROR ,
230+ timestamp = error_data .get ("timestamp" ),
231+ details = parsed_details ,
232+ trace_id = parsed_trace_id ,
233+ )
232234
233- if error_code .startswith ("RES_" ):
234- return TransportNotFoundError (
235- error_code = error_code ,
236- message = error_data .get ("message" ) or _UNKNOWN_ERROR ,
237- timestamp = error_data .get ("timestamp" ),
238- details = parsed_details ,
239- )
235+ if error_code .startswith ("AUTHZ_" ):
236+ return TransportAuthorizationError (
237+ error_code = error_code ,
238+ message = error_data .get ("message" ) or _UNKNOWN_ERROR ,
239+ timestamp = error_data .get ("timestamp" ),
240+ details = parsed_details ,
241+ trace_id = parsed_trace_id ,
242+ )
240243
241- if error_code .startswith ("INT_" ):
242- return TransportServerError (
243- error_code = error_code ,
244- message = error_data .get ("message" ) or _UNKNOWN_ERROR ,
245- timestamp = error_data .get ("timestamp" ),
246- details = parsed_details ,
247- )
244+ if error_code .startswith ("VAL_" ):
245+ return TransportValidationError (
246+ error_code = error_code ,
247+ message = error_data .get ("message" ) or _UNKNOWN_ERROR ,
248+ timestamp = error_data .get ("timestamp" ),
249+ details = parsed_details ,
250+ trace_id = parsed_trace_id ,
251+ )
248252
249- return TransportError (
253+ if error_code .startswith ("RES_" ):
254+ return TransportNotFoundError (
250255 error_code = error_code ,
251256 message = error_data .get ("message" ) or _UNKNOWN_ERROR ,
252257 timestamp = error_data .get ("timestamp" ),
253258 details = parsed_details ,
259+ trace_id = parsed_trace_id ,
254260 )
255261
256- return TransportError (error_code = "SDK_ERROR" , message = error_message )
262+ if error_code .startswith ("INT_" ):
263+ return TransportServerError (
264+ error_code = error_code ,
265+ message = error_data .get ("message" ) or _UNKNOWN_ERROR ,
266+ timestamp = error_data .get ("timestamp" ),
267+ details = parsed_details ,
268+ trace_id = parsed_trace_id ,
269+ )
270+
271+ return TransportError (
272+ error_code = error_code ,
273+ message = error_data .get ("message" ) or _UNKNOWN_ERROR ,
274+ timestamp = error_data .get ("timestamp" ),
275+ details = parsed_details ,
276+ trace_id = parsed_trace_id ,
277+ )
278+
279+ return TransportError (error_code = "SDK_ERROR" , message = error_message , trace_id = trace_id )
257280
258281 except Exception as ex :
259- return TransportError (error_code = "SDK_ERROR" , message = str (ex ))
282+ return TransportError (error_code = "SDK_ERROR" , message = str (ex ), trace_id = trace_id )
0 commit comments