Skip to content
Open
27 changes: 19 additions & 8 deletions client/qiskit_serverless/utils/json.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,17 +139,28 @@ def safe_json_request(
if error_message:
raise QiskitServerlessException(error_message)

if response is not None and not response.ok:
raise QiskitServerlessException(
format_err_msg(
response.status_code,
str(response.text),
)
)

decoding_error_message: Optional[str] = None
try:
json_data = json.loads(response.text)
if response is not None and not response.ok:
# When response is not ok, the expected json
# response is a dictionary with a field
# that contains the error message. The key
# varies between messages, so appending all
# values to a string allows to capture all
# potential messages
print("RESPONSE JSON", json_data)
error_msg = ""
for error_string in json_data.values():
error_msg += str(error_string)
print("ERROR MSG", error_msg)

raise QiskitServerlessException(
format_err_msg(
response.status_code,
str(error_msg),
)
)
except json.JSONDecodeError as json_error:
decoding_error_message = format_err_msg(
ErrorCodes.JSON1001,
Expand Down
26 changes: 22 additions & 4 deletions gateway/api/views/programs.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

Version views inherit from the different views.
"""

import logging
import os

Expand Down Expand Up @@ -290,15 +291,32 @@ def get_by_title(self, request, title):
title=function_title,
provider_name=provider_name,
)
if function is None:
return Response(
{
"message": (
f"Program '{function_title}' for provider '{provider_name}' "
"was not found or you do not have permission to view it."
)
},
status=status.HTTP_404_NOT_FOUND,
)
else:
function = self.function_repository.get_user_function(
author=author, title=function_title
)
if function is None:
return Response(
{
"message": (
f"User program '{function_title}' was not found or "
"you do not have permission to view it."
)
},
status=status.HTTP_404_NOT_FOUND,
)

if function:
return Response(self.get_serializer(function).data)

return Response(status=404)
return Response(self.get_serializer(function).data)

# This end-point is deprecated and we need to confirm if we can remove it
@_trace
Expand Down
17 changes: 17 additions & 0 deletions releasenotes/notes/improve-exception-404-9815392d005df623.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
fixes:
- |
Fixed a bug in the json decoder that would crop the response details to the first character when
gateway errors were raised. This utility now forwards the full error message to the raised
``QiskitServerlessException``.

- |
Fixed error handling when a function is not found. Instead of providing a
bare 404 error, the ``QiskitServerlessException`` now contains a more meaningful error message::

QiskitServerlessException:
| Message: Http bad request.
| Code: 404
| Details: User program 'my-program' was not found or you do not have permission to view it.

Fixes https://github.com/Qiskit/qiskit-serverless/issues/1773.
21 changes: 21 additions & 0 deletions tests/docker/test_docker.py
Original file line number Diff line number Diff line change
Expand Up @@ -390,3 +390,24 @@ def test_get_filtered_jobs(self, serverless_client: ServerlessClient):

succeeded_jobs = serverless_client.jobs(status="SUCCEEDED")
assert len(succeeded_jobs) >= 3

def test_wrong_function_name(self, serverless_client: ServerlessClient):
"""Integration test for retrieving a function that isn't accessible."""

arguments_function = QiskitFunction(
title="pattern-with-arguments",
entrypoint="pattern_with_arguments.py",
working_dir=resources_path,
)

expected_message = (
"User program 'wrong-title' was not found or you do not "
"have permission to view it."
)

serverless_client.upload(arguments_function)

with raises(QiskitServerlessException) as exc_info:
serverless_client.function("wrong-title")

assert str(exc_info.value) == expected_message
Loading