graphql-engine icon indicating copy to clipboard operation
graphql-engine copied to clipboard

Hasura doesn't show RAISE EXCEPTION message from postgres function

Open pronevich opened this issue 6 years ago • 25 comments

It's common to make some checks in triggers and RAISE NOTICE or EXCEPTION and provided message went to postgres log. Can we somehow provide this message to the client, instead poor Uncaught (in promise) Error: GraphQL error: postgres query error

pronevich avatar Jul 25 '19 13:07 pronevich

Any update? I think this is really needed for any kind of serious app with validations.

michaelhayman avatar Sep 10 '19 08:09 michaelhayman

Capturing postgres errors and propagating them to the client side is easy however we shouldn't be capturing every error, only those that are meant for the client.

The question is how do we distinguish these errors? Luckily Postgres lets you define custom error codes (through SQLSTATE). So maybe we can provide a server side flag, say, CAPTURE_SQLSTATE? The server will capture errors with that particular error state and propagate them to the client. Your validation logic should use this error code if you want to propagate the error to the client.

0x777 avatar Sep 10 '19 08:09 0x777

@0x777 that would be great. It would also be helpful if that check support a prefix or a pattern/mask to be configured, this could be in accordance to what is specified in the documentation.

When specifying an error code by SQLSTATE code, you are not limited to the predefined error codes, but can select any error code consisting of five digits and/or upper-case ASCII letters, other than 00000. It is recommended that you avoid throwing error codes that end in three zeroes, because these are category codes and can only be trapped by trapping the whole category.

In our use case today, we have a helper function (example below) that raises all exceptions that we want to propagate to the client. We use a prefix (eg: C0) to the code in order to indicate such application errors.

CREATE FUNCTION errors.raise(
  code_    TEXT DEFAULT 'C0500',
  message_ TEXT DEFAULT 'Something went wrong while processing your request',
  hint_    TEXT DEFAULT 'Try again later'
) RETURNS VOID
  LANGUAGE plpgsql
  IMMUTABLE STRICT PARALLEL SAFE AS
$function$
BEGIN
  RAISE EXCEPTION USING ERRCODE = code_, MESSAGE = message_, HINT = hint_;
END;
$function$;

It would really helpful if such a usage pattern (including the propagation of HINT) could be supported in the solution for this issue.

abn avatar Sep 15 '19 12:09 abn

@0x777 @dsandip was there any movement/update on this one?

abn avatar Oct 12 '19 20:10 abn

@abn This is definitely something that we want to implement but we haven't added it to our pipeline yet. Hopefully, we can get this out in a couple of releases.

0x777 avatar Oct 14 '19 15:10 0x777

@0x777 that would be amazing; happy to test any PR branches etc or contribute in a similar fashion. Right now we are left with some "string match and guess work" logic in the front end to determine how best to feedback to the user.

abn avatar Oct 21 '19 10:10 abn

Any update on this? This feature is pretty much needed.

iamkhalidbashir avatar Nov 22 '19 21:11 iamkhalidbashir

https://blog.hasura.io/postgres-triggers-on-graphql-mutations-682bf48db023/

This blog post raises the exception and is received by the client, but the same doesn't happen on our hasura client front

iamkhalidbashir avatar Nov 22 '19 21:11 iamkhalidbashir

Cause Hasura doesn't show RAISE EXCEPTION message, maybe I should create a new table to store the error messages for different tables, and then return NULL. 😁 😅

Chris533 avatar Dec 03 '19 15:12 Chris533

It raises proper exceptions if you use hasura-admin-secret but will fail if you use jwt authorization.

rohit-32 avatar Jan 15 '20 18:01 rohit-32

Any progress on this one? With iffy inbound data into our database (i.e. any realistic use case) we need to be able to handle cases where data is unavailable for a GraphQL query. Postgresql exceptions seem to be the way to go in order to handle these.

dvasdekis avatar Feb 10 '20 23:02 dvasdekis

@dvasdekis This issue is something we would like to pick up and we are figuring out its priority.

marionschleifer avatar Feb 12 '20 10:02 marionschleifer

I'm having the same problem of @rohit-32... if hasura has a jwt configured and defined Authorization header, Graphql show as answer postgres query error not throwing the error.

Contextualizing: I have a trigger function, that realizes some checks and if it is invalid then raise an exception.

Captura de Tela 2020-02-14 às 23 46 21

http log:

{
  "type":"http-log",
  "timestamp":"2020-02-15T02:43:52.897+0000",
  "level":"error",
  "detail":{
    "operation":{
      "user_vars":{
        "x-hasura-role":"user",
        "x-hasura-user-id":"2f589e70-c029-4aed-a4de-f06620444fa7"
      },
      "error":{
        "internal":{
          "statement":"WITH \"public_user_groups__mutation_result_alias\" AS (INSERT INTO \"hdb_views\".\"user__insert__public__user_groups\" ( \"updated_at\", \"created_at\", \"quotas\", \"id\", \"group_id\", \"user_id\" ) VALUES (DEFAULT, DEFAULT, $2, DEFAULT, $1, ((current_setting('hasura.user')::json->>'x-hasura-user-id'))::uuid)  RETURNING * ) SELECT  json_build_object('affected_rows', (SELECT  COUNT(*)  FROM \"public_user_groups__mutation_result_alias\"      ) )        ",
          "prepared":true,
          "error":{
            "exec_status":"FatalError",
            "hint":null,
            "message":"CURRENT QUOTA VALUE IS EXCEEDING THE CURRENT QUOTA (MAX_QUOTAS (5) - TO_INSERT (4))",
            "status_code":"P0001",
            "description":null
          },
          "arguments":[
            "(Oid 0,Just (\"5803e53d-55e1-4e32-bd47-581d330b4fc5\",Text))",
            "(Oid 23,Just (\"\\NUL\\NUL\\NUL\\EOT\",Binary))"
          ]
        },
        "path":"$.selectionSet.insert_user_groups.args.objects",
        "error":"postgres query error",
        "code":"unexpected"
      },
      "request_id":"2e94b56d-2702-4b30-9796-9035d669fa29",
      "response_size":922,
      "query":{
        "variables":{
          "groupId":"5803e53d-55e1-4e32-bd47-581d330b4fc5"
        },
        "operationName":"enterGroup",
        "query":"mutation enterGroup($groupId: uuid) {\n  insert_user_groups(objects: {group_id: $groupId, quotas: 4}) {\n    affected_rows\n  }\n}\n"
      }
    },
    "http_info":{
      "status":200,
      "http_version":"HTTP/1.1",
      "url":"/v1/graphql",
      "ip":"172.19.0.1",
      "method":"POST",
      "content_encoding":null
    }
  }
}

trigger: https://gist.github.com/mandado/2d074b1d975a026111b224e96e62bb11

mandado avatar Feb 15 '20 02:02 mandado

Same here. We're having a BEFORE INSERT ON trigger on a table that makes certain validations and raises an exception when the insert operation is not allowed. This ends up as

path: "$.selectionSet.insert_entity.args.objects"
code: "unexpected"
message: "postgres query error"

in the response. The raised exception message is no where to be seen, which we'd like.

codepunkt avatar Mar 06 '20 11:03 codepunkt

Having the same issue when I include "x-hasura-role" as header in dashboard I get

{ "errors": [ { "extensions": { "path": "$", "code": "unexpected" }, "message": "postgres query error" } ] }

wlans avatar Mar 18 '20 03:03 wlans

Would it be possible to whitelist which errors code(prefix?) are allowed to be shown client side? Like we do for graphql queries.

--postgres-errors-prefix-whitelist=TXXA HASURA_POSTGRES_ERROS_PREFIX_WHITELIST=TXXA

jchonde avatar Apr 19 '20 10:04 jchonde

It seems to be fixed in the last Hasura release https://github.com/hasura/graphql-engine/releases/tag/v1.2.0-beta.5 You have to put HASURA_GRAPHQL_DEV_MODE as true or start the server with --dev-mode flag.

I'm wondering why they consider this a dev setting while our usecase is pretty common ?

DavoCg avatar Apr 25 '20 07:04 DavoCg

Having the same issue here. @DavoCg Maybe it's for security purpose. I don't want users can see the table structures too. But it's really really helpful if the errcodes can be exposed.

leiwan5 avatar May 12 '20 14:05 leiwan5

@abn This is definitely something that we want to implement but we haven't added it to our pipeline yet. Hopefully, we can get this out in a couple of releases.

Any update on this feature? This would be great

sasog23 avatar Aug 05 '20 13:08 sasog23

@abn This is definitely something that we want to implement but we haven't added it to our pipeline yet. Hopefully, we can get this out in a couple of releases.

Any update on this feature? This would be great

This is a must feature.We really need this feature. When it will be available?

sokolej79 avatar Aug 07 '20 05:08 sokolej79

anything new on this feature request?

sasog23 avatar Sep 08 '20 08:09 sasog23

I guess you can use Class 22 — Data Exception error codes

raise exception like this RAISE EXCEPTION USING ERRCODE= '22000', MESSAGE= 'business logic error message';

and the client will always receive { "errors": [ { "extensions": { "path": "$", "code": "data-exception" }, "message": "business logic error message" } ] }

https://www.postgresql.org/docs/current/errcodes-appendix.html

sasog23 avatar Oct 09 '20 05:10 sasog23

Not sure this is needed anymore since you can set ERRCODE and that'll cause the message to show. Awesome find, @sasog23!! Exactly what I was hoping for.

I'm not an expert here but I'm not sure NOTICE level messages could ever be passed through because of the way graphql clients expect responses. setting the errors field signifies an error for a graphql client, and would probably throw.

Maybe it would make sense to change the scope of this issue to target passing other exception info, like HINT and DETAILS.

ferm10n avatar Jul 20 '21 21:07 ferm10n

any update on this, since this is required for https://github.com/hasura/graphql-engine/issues/7498

abdullah2993 avatar Jun 13 '22 14:06 abdullah2993

use this code it's work

RAISE EXCEPTION USING ERRCODE = '22000', MESSAGE = 'Event is full';

for ERRCODE number you can only use in this list https://www.postgresql.org/docs/current/errcodes-appendix.html

divemotion avatar Jul 25 '22 19:07 divemotion