6262
6363
6464class ParamResolutionError (Exception ):
65- """Raised when a path parameter cannot be resolved for entity probing."""
65+ """Raised when a path parameter cannot be resolved for entity probing.
66+
67+ Covers structural resolution failures (unresolvable param, self-reference,
68+ parent with no LIST op, parent returning no records, missing parent key,
69+ max recursion depth). ``_probe_entity`` converts these into UNHEALTHY
70+ results so the backend controller classifies them as INCONCLUSIVE. SKIPPED
71+ is reserved exclusively for "this entity has no list/get action at all".
72+
73+ Execution failures from probing a parent entity use ParentProbeError
74+ instead, so the child can inherit the parent's ``status_code`` for
75+ 401/403 -> FAILED classification.
76+ """
77+
78+
79+ class ParentProbeError (Exception ):
80+ """Raised when a parent entity's LIST probe fails during param resolution.
81+
82+ Wraps the original exception's message with parent-entity context for
83+ debuggability, while preserving the parent's ``status_code`` so the child
84+ can be classified the same way the parent would be (401/403 -> FAILED,
85+ everything else -> INCONCLUSIVE at the backend controller layer).
86+
87+ Distinct from ``ParamResolutionError`` so the ``status_code`` survives --
88+ both route through ``_probe_entity``'s UNHEALTHY branch, but only
89+ ParentProbeError carries the parent's HTTP status.
90+ """
91+
92+ def __init__ (self , message : str , status_code : int | None = None ) -> None :
93+ super ().__init__ (message )
94+ self .status_code = status_code
6695
6796
6897class _OperationContext :
@@ -727,9 +756,7 @@ async def _probe_entity(
727756 # Also resolve query params that have a matching scoping or config
728757 # key, so explicit config values take precedence over defaults.
729758 for qp in endpoint .query_params :
730- if qp not in params_needing_resolution and (
731- qp in self ._scoping_index or qp in self .config_values
732- ):
759+ if qp not in params_needing_resolution and (qp in self ._scoping_index or qp in self .config_values ):
733760 params_needing_resolution .append (qp )
734761 if params_needing_resolution :
735762 try :
@@ -744,7 +771,7 @@ async def _probe_entity(
744771 except ParamResolutionError as exc :
745772 return {
746773 "entity" : entity_name ,
747- "status" : CHECK_STATUS_SKIPPED ,
774+ "status" : CHECK_STATUS_UNHEALTHY ,
748775 "error" : str (exc ),
749776 "status_code" : None ,
750777 "checked_action" : action .value ,
@@ -846,7 +873,10 @@ async def _resolve_path_params(
846873 parent_params ,
847874 )
848875 except Exception as exc :
849- raise ParamResolutionError (f"Parent entity '{ parent_entity_name } ' probe failed: { exc } " ) from exc
876+ raise ParentProbeError (
877+ f"Parent entity '{ parent_entity_name } ' probe failed: { exc } " ,
878+ status_code = getattr (exc , "status_code" , None ),
879+ ) from exc
850880 records = result .data if isinstance (result .data , list ) else []
851881 if not records :
852882 raise ParamResolutionError (f"Parent entity '{ parent_entity_name } ' returned no records" )
0 commit comments