From 6a18d99fc12286c707712a3e05f71a8bd6c631fe Mon Sep 17 00:00:00 2001 From: Aryan Kansagara Date: Fri, 11 Sep 2026 02:19:27 -0400 Subject: [PATCH] fix: API Server - Return 404 from /api/executions/{id}/state when execution does not exist get_graph_execution_state built its response purely by counting child execution nodes, so an unknown execution id produced an empty count and was reported as HTTP 200 with has_ended=True. Callers could not tell a finished graph from a missing one. Check that the ExecutionNode exists before counting and raise ItemNotFoundError otherwise, matching get_container_execution_state. The router already maps ItemNotFoundError to a 404 response, so both /api/executions/{id}/state and /api/executions/{id}/graph_execution_state now return 404 for unknown ids. Closes #49 Signed-off-by: Aryan Kansagara --- cloud_pipelines_backend/api_server_sql.py | 2 ++ tests/test_execution_nodes_api_service.py | 7 +++++++ 2 files changed, 9 insertions(+) diff --git a/cloud_pipelines_backend/api_server_sql.py b/cloud_pipelines_backend/api_server_sql.py index 451f079..a308176 100644 --- a/cloud_pipelines_backend/api_server_sql.py +++ b/cloud_pipelines_backend/api_server_sql.py @@ -666,6 +666,8 @@ def get(self, session: orm.Session, id: bts.IdType) -> GetExecutionInfoResponse: def get_graph_execution_state( self, session: orm.Session, id: bts.IdType ) -> GetGraphExecutionStateResponse: + if not session.get(bts.ExecutionNode, id): + raise errors.ItemNotFoundError(f"Execution with {id=} does not exist.") ExecutionNode_Child = orm.aliased( bts.ExecutionNode, name="child_execution_node" ) diff --git a/tests/test_execution_nodes_api_service.py b/tests/test_execution_nodes_api_service.py index 9663795..1b3ec1e 100644 --- a/tests/test_execution_nodes_api_service.py +++ b/tests/test_execution_nodes_api_service.py @@ -90,6 +90,13 @@ def test_no_children_returns_empty_stats(self): assert result.child_execution_status_summary.ended_executions == 0 assert result.child_execution_status_summary.has_ended is True + def test_missing_execution_raises_not_found(self): + """An absent execution raises ItemNotFoundError (404) instead of + returning empty stats that look like a finished graph.""" + with self.session_factory() as session: + with pytest.raises(errors.ItemNotFoundError): + self.service.get_graph_execution_state(session, "does-not-exist") + def test_children_with_no_status_are_excluded(self): """Children whose container_execution_status is None are not counted.""" with self.session_factory() as session: