-
Notifications
You must be signed in to change notification settings - Fork 2.8k
Description
Version Information
Server Version: 2.48.3
Environment
OSS
What is the current behaviour?
When enabling the experimental flag remove_empty_subscription_responses
, and starting a subscription with no results, we get the following database query error
:
FatalError
cannot get array length of a non-array
Subscriptions with results don’t seem affected.
What is the expected behaviour?
We should get a response with an empty array as is the case without the flag.
How to reproduce the issue?
- Start Hasura with env variable
HASURA_GRAPHQL_EXPERIMENTAL_FEATURES
set toremove_empty_subscription_responses
- Make a subscription with filters so that there is no selected row
cannot get array length of a non-array
Please provide any traces or logs that could help here.
Log from such an error this morning
{
"detail": {
"connection_info": {
"msg": null,
"token_expiry": null,
"websocket_id": "c6d135c6-caa4-4d2d-a01b-c88a40778d02"
},
"event": {
"detail": {
"operation_id": "c30a0851-8cd8-4ee0-860a-be1faec429e0",
"operation_name": null,
"operation_type": {
"detail": {
"code": "unexpected",
"error": "database query error",
"internal": {
"arguments": [
"(Oid 705,Just (\"\\NUL\\NUL\\NUL\\SOH\\NUL\\NUL\\NUL\\NUL\\NUL\\NUL\\v\\134\\NUL\\NUL\\NUL\\SOH\\NUL\\NUL\\NUL\\SOH\\NUL\\NUL\\NUL\\DLE\\206\\ENQM#\\ETB\\167E\\DC4\\135<\\229\\175w`<\\143\",Binary))",
"(Oid 3807,Just (\"\\NUL\\NUL\\NUL\\SOH\\NUL\\NUL\\NUL\\NUL\\NUL\\NUL\\SO\\218\\NUL\\NUL\\NUL\\SOH\\NUL\\NUL\\NUL\\SOH\\NUL\\NUL\\NUL\\138\\SOH{\\\"cursor\\\":{},\\\"query\\\":{},\\\"session\\\":{\\\"x-hasura-user-id\\\":\\\"4\\\"},\\\"synthetic\\\":[\\\"0.0\\\",\\\"false\\\",\\\"{-1,5}\\\",\\\"4\\\",\\\"false\\\",\\\"true\\\",\\\"false\\\",\\\"REGULAR\\\",\\\"0\\\"]}\",Binary))"
],
"error": {
"description": null,
"exec_status": "FatalError",
"hint": null,
"message": "cannot get array length of a non-array",
"status_code": "22023"
},
"prepared": true,
"statement": "SELECT * FROM (SELECT \"__subs\".\"result_id\" , \"__fld_resp\".\"root\" AS \"result\" FROM UNNEST(($1)::uuid[], ($2)::json[]) AS \"__subs\"(\"result_id\", \"result_vars\") LEFT OUTER JOIN LATERAL (SELECT json_build_object('user_user_aggregate', \"_user_user_aggregate\".\"root\" ) AS \"root\" FROM (SELECT json_build_object('aggregate', json_build_object('count', COUNT(*) ) ) AS \"root\" FROM (SELECT 1 FROM (SELECT * FROM \"public\".\"user_user\" WHERE ((EXISTS (SELECT 1 FROM \"public\".\"user_user\" AS \"__exists_table_0\" WHERE ((((((\"__exists_table_0\".\"id\") = (((\"__subs\".\"result_vars\"#>>ARRAY['session', 'x-hasura-user-id']))::integer)) AND ('true')) AND ('true')) AND (((((\"__exists_table_0\".\"is_active\") = (('true')::boolean)) AND ('true')) AND ('true')) AND (((((\"__exists_table_0\".\"first_login\") = (('false')::boolean)) AND ('true')) AND ('true')) AND ('true')))) AND ('true')) )) AND ((EXISTS (SELECT 1 FROM \"public\".\"invoice_salary\" AS \"__be_1_invoice_salary\" WHERE ((((\"__be_1_invoice_salary\".\"payed_id\") = (\"public\".\"user_user\".\"id\")) AND ('true')) AND (((EXISTS (SELECT 1 FROM \"public\".\"user_user\" AS \"__exists_table_2\" WHERE ((((((\"__exists_table_2\".\"id\") = (((\"__subs\".\"result_vars\"#>>ARRAY['session', 'x-hasura-user-id']))::integer)) AND ('true')) AND ('true')) AND (((((\"__exists_table_2\".\"is_active\") = (('true')::boolean)) AND ('true')) AND ('true')) AND (((((\"__exists_table_2\".\"first_login\") = (('false')::boolean)) AND ('true')) AND ('true')) AND ('true')))) AND ('true')) )) AND ('true')) AND ((((\"__be_1_invoice_salary\".\"to_pay\") > (((\"__subs\".\"result_vars\"#>>ARRAY['synthetic', '0']))::numeric)) AND ('true')) AND ((EXISTS (SELECT 1 FROM \"public\".\"invoice_invoice\" AS \"__be_3_invoice_invoice\" WHERE ((((\"__be_3_invoice_invoice\".\"id\") = (\"__be_1_invoice_salary\".\"invoice_id\")) AND ('true')) AND (((EXISTS (SELECT 1 FROM \"public\".\"user_user\" AS \"__exists_table_4\" WHERE ((((((\"__exists_table_4\".\"id\") = (((\"__subs\".\"result_vars\"#>>ARRAY['session', 'x-hasura-user-id']))::integer)) AND ('true')) AND ('true')) AND (((((\"__exists_table_4\".\"is_active\") = (('true')::boolean)) AND ('true')) AND ('true')) AND (((((\"__exists_table_4\".\"first_login\") = (('false')::boolean)) AND ('true')) AND ('true')) AND ('true')))) AND ('true')) )) AND ('true')) AND ((((\"__be_3_invoice_invoice\".\"abandonned\") = (((\"__subs\".\"result_vars\"#>>ARRAY['synthetic', '1']))::boolean)) AND ('true')) AND ('true')))) )) AND (((NOT ((\"__be_1_invoice_salary\".\"state\") = ANY(((\"__subs\".\"result_vars\"#>>ARRAY['synthetic', '2']))::integer[]))) AND ('true')) AND ('true')))))) )) AND (((\"public\".\"user_user\".\"referent_id\") = (((\"__subs\".\"result_vars\"#>>ARRAY['synthetic', '3']))::integer)) AND ((EXISTS (SELECT 1 FROM \"public\".\"student_student\" AS \"__be_5_student_student\" WHERE ((((\"__be_5_student_student\".\"user_id\") = (\"public\".\"user_user\".\"id\")) AND ('true')) AND (((EXISTS (SELECT 1 FROM \"public\".\"user_user\" AS \"__exists_table_6\" WHERE ((((((\"__exists_table_6\".\"id\") = (((\"__subs\".\"result_vars\"#>>ARRAY['session', 'x-hasura-user-id']))::integer)) AND ('true')) AND ('true')) AND (((((\"__exists_table_6\".\"is_active\") = (('true')::boolean)) AND ('true')) AND ('true')) AND (((((\"__exists_table_6\".\"first_login\") = (('false')::boolean)) AND ('true')) AND ('true')) AND (((((\"__exists_table_6\".\"is_staff\") = (('true')::boolean)) AND ('true')) AND ('true')) AND ('true'))))) AND ('true')) )) AND ('true')) AND ((((\"__be_5_student_student\".\"mgp_nationality_blocked\") = (((\"__subs\".\"result_vars\"#>>ARRAY['synthetic', '4']))::boolean)) AND ('true')) AND ((((((\"__be_5_student_student\".\"need_sca_enroll\") = (((\"__subs\".\"result_vars\"#>>ARRAY['synthetic', '5']))::boolean)) AND ('true')) AND ('true')) OR (((((\"__be_5_student_student\".\"has_active_recipient\") = (((\"__subs\".\"result_vars\"#>>ARRAY['synthetic', '6']))::boolean)) AND ('true')) AND ('true')) OR ('false'))) AND ('true'))))) )) OR (EXISTS (SELECT 1 FROM (SELECT count(* ) AS \"mango_pay_naturaluser_count\" FROM \"public\".\"mango_pay_naturaluser\" AS \"__be_7_mango_pay_naturaluser\" WHERE (((\"__be_7_mango_pay_naturaluser\".\"user_id\") = (\"public\".\"user_user\".\"id\")) AND ((EXISTS (SELECT 1 FROM \"public\".\"user_user\" AS \"__exists_table_8\" WHERE ((((((\"__exists_table_8\".\"id\") = (((\"__subs\".\"result_vars\"#>>ARRAY['session', 'x-hasura-user-id']))::integer)) AND ('true')) AND ('true')) AND (((((\"__exists_table_8\".\"is_active\") = (('true')::boolean)) AND ('true')) AND ('true')) AND (((((\"__exists_table_8\".\"first_login\") = (('false')::boolean)) AND ('true')) AND ('true')) AND ('true')))) AND ('true')) )) AND ((\"__be_7_mango_pay_naturaluser\".\"kyc_level\") = (((\"__subs\".\"result_vars\"#>>ARRAY['synthetic', '7']))::\"mgp_naturaluser_kyc_level\")))) ) AS \"__sub\" WHERE ((\"__sub\".\"mango_pay_naturaluser_count\") = (((\"__subs\".\"result_vars\"#>>ARRAY['synthetic', '8']))::integer)) )))))) ) AS \"_root.base\" ) AS \"_root\" ) AS \"_user_user_aggregate\" ) AS \"__fld_resp\" ON ('true') ) AS \"__multiplex\" WHERE (EXISTS (SELECT 1 FROM \"json_each\"(\"result\") WHERE ((json_array_length(\"value\" )) > ('0')) )) "
},
"path": "$"
},
"type": "query_err"
},
"parameterized_query_hash": null,
"query": null,
"request_id": "3e76a5fb-fef1-4755-b1a8-a35d95c42155"
},
"type": "operation"
},
"user_vars": {
"x-hasura-role": "staff",
"x-hasura-user-id": "4"
}
},
"level": "error",
"timestamp": "2025-07-29T10:26:17.819+0000",
"type": "websocket-log"
}
Any possible solutions/workarounds you're aware of?
Disabling the feature makes the subscription work again, but we were hoping that it would reduce our Postgresql server load (see #9994).
Extra note
I wanted to make a smaller subscription directly from the web console to provide it along a shorter log but GraphiQL doesn’t work because it tries to POST to https://v1/graphql
, ignoring the domain name.
I am unsure whether this warrant a new issue (the flag has no incidence on it) or is a problem on my end (perhaps a faulty browser cache)