Check out v4 of the Fauna CLI

v4 of the Fauna CLI is now GA.

The new version introduces enhancements to the developer experience, including an improved authentication workflow. To get started, check out the CLI v4 quick start.

Migrating from v3 of the CLI? See the CLI migration guide.

Query summary

Responses from the Fauna Core HTTP API’s Query endpoint include a summary property containing a JSON-escaped string.

The summary contains a human-readable description of errors, warnings, or custom messages returned by the query. If an error or warning, the summary includes the location of the issue and a hint for resolving it, if applicable.

summary can contain multiple messages, which are separated using a newline.

Error summaries

Error responses include a summary that describes the issue causing the error.

For example, the following FQL query attempts to create and call a collection in the same query:

Collection.create({name: "Foo"})

Collection("Foo").create({ bar: "baz"})

The query as a Query endpoint request:

curl -X POST \
'https://db.fauna.com/query/1' \
-H "Authorization: Bearer $FAUNA_SECRET" \
-H 'Content-Type: application/json' \
-H 'X-Format: tagged' \
-d '{
  "query": "Collection.create({name: \"Foo\"})\n\nCollection(\"Foo\").create({ bar: \"baz\"})"
}'

Response:

{
  "error": {
    "code": "invalid_argument",
    "message": "invalid argument `collection`: No such user collection `Foo`."
  },
  "summary": "error: invalid argument `collection`: No such user collection `Foo`.\nat *query*:3:11\n  |\n3 | Collection(\"Foo\").create({ bar: \"baz\"})\n  |           ^^^^^^^\n  |\nhint: A collection cannot be created and used in the same query.\n  |\n3 | Collection(\"Foo\").create({ bar: \"baz\"})\n  |           ^^^^^^^\n  |",
  ...
}

When unescaped, the response’s summary renders as:

error: invalid argument `collection`: No such user collection `Foo`.
at *query*:3:11
  |
3 | Collection("Foo").create({ bar: "baz"})
  |           ^^^^^^^
  |
hint: A collection cannot be created and used in the same query.
  |
3 | Collection("Foo").create({ bar: "baz"})
  |           ^^^^^^^
  |

Abort error summaries

Abort errors include a query stack trace in the response’s summary field. The stack trace includes the lines that triggered the error.

For example, the following FQL query includes an abort() call:

Customer.all()
abort("Discard")

The query as a Query endpoint request:

curl -X POST \
'https://db.fauna.com/query/1' \
-H "Authorization: Bearer $FAUNA_SECRET" \
-H 'Content-Type: application/json' \
-H 'X-Format: tagged' \
-d '{
  "query": "Customer.all()\nabort(\"Discard\")"
}'

Response:

{
    "error": {
        "code": "abort",
        "message": "Query aborted.",
        "abort": "Discard"
    },
    "summary": "error: Query aborted.\nat *query*:2:6\n  |\n2 | abort(\"Discard\")\n  |      ^^^^^^^^^^^\n  |",
    ...
}

When unescaped, the response’s summary renders as:

error: Query aborted.
at *query*:2:6
  |
2 | abort("Discard")
  |      ^^^^^^^^^^^
  |

Query stack traces for UDF calls

When calling a user-defined function (UDF) that uses abort(), the summary’s query stack trace includes both query and UDF lines if the authentication secret has the built-in admin or server role.

For example, the following response’s summary field contains a query stack trace with both query and UDF lines:

{
  "error": {
      "code": "abort",
      "message": "Query aborted.",
      "abort": "Can not call checkout with status other than processing."
  },
  "summary": "error: Query aborted.\nat *udf:checkout*:6:10\n  |\n6 | abort(\"Can not call checkout with status other than processing.\")\n  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n  |\nat *query*:1:9\n  |\n1 | checkout(420701723228635213, \"cart\", {})\n  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n  |\n\ninfo at *udf:checkout*:3: log - test123\n\ninfo: \"debug - test123\"\nat *udf:checkout*:4:6\n  |\n4 | dbg(\"debug - test123\")\n  |      ^^^^^^^^^^^^^^^^^^^\n  |",
  ...
}

When unescaped, the response’s summary renders as:

error: Query aborted.
at *udf:checkout*:6:10
  |
6 | abort("Can not call checkout with status other than processing.")
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  |
at *query*:1:9
  |
1 | checkout(420701723228635213, "cart", {})
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  |

info at *udf:checkout*:3: log - test123

info: "debug - test123"
at *udf:checkout*:4:6
  |
4 | dbg("debug - test123")
  |      ^^^^^^^^^^^^^^^^^^^
  |

For secrets with the built-in server-readonly role or a user-defined role, the summary’s stack trace only includes query lines, not UDF lines. This applies even if the UDF is annotated with @role(admin) or @role(server). This prevents unprivileged users from inferring sensitive UDF logic or data.

For example, the previous response’s summary field contains a query stack trace with only query lines:

{
  "error": {
      "code": "abort",
      "message": "Query aborted.",
      "abort": "Can not call checkout with status other than processing."
  },
  "summary": "error: Query aborted.\nat *query*:1:9\n  |\n1 | checkout(420701723228635213, \"cart\", {})\n  |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n  |",
  ...
}

When unescaped, the response’s summary renders as:

error: Query aborted.
at *query*:1:9
  |
1 | checkout(420701723228635213, "cart", {})
  |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  |

Warning summaries

If typechecking is enabled, queries that include a built-in method but don’t call the method return a warning in the summary.

For example, the following FQL query omits the parentheses (()) on a Time.now() call:

Time.now

The query as a Query endpoint request:

 curl -X POST \
  'https://db.fauna.com/query/1' \
  -H 'Authorization: Bearer <FAUNA_SECRET>' \
  -H 'Content-Type: application/json' \
  -H 'X-Format: tagged' \
  -d '{
    "query": "Time.now"
  }'

Response:

{
  "data": "[function now()]",
  "static_type": "() => Time",
  "summary": "warning: Function is not called.\nat *query*:1:1\n  |\n1 | Time.now\n  | ^^^^^^^^\n  |\nhint: Call the function.\n  |\n1 | Time.now()\n  |         ++\n  |",
  ...
}

When unescaped, the response’s summary renders as:

warning: Function is not called.
at *query*:1:1
  |
1 | Time.now
  | ^^^^^^^^
  |
hint: Call the function.
  |
1 | Time.now()
  |         ++
  |

Similarly, queries that include an anonymous function but don’t call the FQL return a warning in the summary.

For example, the following FQL query defines a function but doesn’t call it:

(x, y) => x + y

The query as a Query endpoint request:

 curl -X POST \
  'https://db.fauna.com/query/1' \
  -H 'Authorization: Bearer <FAUNA_SECRET>' \
  -H 'Content-Type: application/json' \
  -H 'X-Format: tagged' \
  -d '{
    "query": "(x, y) => x + y"
  }'

Response:

{
  "data": "[function <lambda>]",
  "static_type": "((Number, Number) => Number) & ((String, String) => String)",
  "summary": "warning: Function is not called.\nat *query*:1:1\n  |\n1 | (x, y) => x + y\n  | ^^^^^^^^^^^^^^^\n  |\nhint: Call the function.\n  |\n1 | (x, y) => x + y()\n  |                ++\n  |",
  ...
}

When unescaped, the response’s summary renders as:

warning: Function is not called.
at *query*:1:1
  |
1 | (x, y) => x + y
  | ^^^^^^^^^^^^^^^
  |
hint: Call the function.
  |
1 | (x, y) => x + y()
  |                ++
  |

Log and debug messages

You can use the log() and dbg() FQL methods to pass custom messages to the summary.

Log messages

Use log() to pass messages to the summary. The messages are annotated as info.

log() is similar to console.log() or print() in other programming languages. log() supports interpolated strings containing FQL variables.

For example, the following FQL query logs several summary messages:

log("Before assignment")
let x = 5
let y = { lat: 37.5542782, long: -122.3007394 }
log("After assignment x=#{x}")
log(y)
x

The query as a Query endpoint request:

 curl -X POST \
  'https://db.fauna.com/query/1' \
  -H 'Authorization: Bearer <FAUNA_SECRET>' \
  -H 'Content-Type: application/json' \
  -H 'X-Format: tagged' \
  -d '{
    "query": "log(\"Before assignment\")\nlet x = 5\nlet y = { lat: 37.5542782, long: -122.3007394 }\nlog(\"After assignment x=#{x}\")\nlog(y)\nx\n"
  }'

Unlike dbg(), log() does not return a value. The message is excluded from the query results in data.

The summary includes the query lines that called log():

{
  "data": {
    "@int": "5"
  },
  "static_type": "5",
  "summary": "info at *query*:1: Before assignment\n\ninfo at *query*:4: After assignment x=5\n\ninfo at *query*:5: { lat: 37.5542782, long: -122.3007394 }",
  ...
}

When unescaped, the response’s summary renders as:

info at *query*:1: Before assignment

info at *query*:4: After assignment x=5

info at *query*:5: { lat: 37.5542782, long: -122.3007394 }

Debug messages

dbg() is similar to log() except that it returns its message in the actual query result.

You can use dbg() inline within method calls for debugging.

For example, the following FQL query uses dbg() within a collection.create() call:

let x = "key limes"

Product.create(
  // `dbg()` outputs its message. In this case,
  // it outputs an object containing the `name`
  // and `stock` properties.
  dbg({
    name: "#{x}",
    stock: 1 + 2 + 3,
  })
)

The query as a Query endpoint request:

 curl -X POST \
  'https://db.fauna.com/query/1' \
  -H 'Authorization: Bearer <FAUNA_SECRET>' \
  -H 'Content-Type: application/json' \
  -H 'X-Format: tagged' \
  -d '{
    "query": "let x = \"key limes\"\n\nProduct.create(\n dbg({\n    name: \"#{x}\",\n    stock: 1 + 2 + 3,\n  })\n)"
  }'

The message is included in the query results in data. The summary includes the query lines that called dbg():

{
  "data": {
    "@doc": {
      "id": "413921254218661965",
      "coll": {
        "@mod": "Product"
      },
      "ts": {
        "@time": "2099-11-07T18:41:59.173Z"
      },
      "name": "key limes",
      "stock": {
        "@int": "6"
      }
    }
  },
  "static_type": "Product",
  "summary": "info: { name: \"key limes\", stock: 6 }\nat *query*:4:6\n  |\n4 |     dbg({\n  |  ______^\n5 | |     name: \"#{x}\",\n6 | |     stock: 1 + 2 + 3,\n7 | |   })\n  | |____^\n  |",
  ...
}

When unescaped, the response’s summary renders as:

info: { name: "key limes", stock: 6 }
at *query*:4:6
  |
4 |     dbg({
  |  ______^
5 | |     name: "#{x}",
6 | |     stock: 1 + 2 + 3,
7 | |   })
  | |____^
  |

Log and debug messages for UDF calls

When calling a user-defined function (UDF) that uses log() or dbg(), the visibility of the respective log or debug messages depends on the authentication secret's role:

Role Visibility

Messages are returned in the response’s summary.

Messages are not returned, even if the UDF is annotated with @role(admin) or @role(server).

Performance hints

If a query request’s X-Performance-Hints header is true, responses include performance hints, if applicable, in the summary field.

The hints provide actionable steps for improving the query’s performance. You typically use performance hints when testing or prototyping FQL queries in the Fauna Dashboard Shell.

For example, Fauna emits performance hints for uncovered index queries. The following FQL query uses an index but projects fields that aren’t covered by the index definition:

// This is an uncovered query.
// `stock` is not one of the terms or values
// in the `sortedByPriceLowToHigh()` index definition.
Product.sortedByPriceLowToHigh() { name, stock }

The query as a Query endpoint request:

curl -X POST \
'https://db.fauna.com/query/1' \
-H "Authorization: Bearer $FAUNA_SECRET" \
-H 'Content-Type: application/json' \
-H 'X-Performance-Hints: true' \
-H 'X-Format: tagged' \
-d '{
  "query": "Product.sortedByPriceLowToHigh() { name, stock }"
}'

Response:

{
  ...
  "summary": "performance_hint: non_covered_document_read - .stock is not covered by the Product.sortedByPriceLowToHigh index. See https://docs.fauna.com/performance_hint/non_covered_document_read.\nat *query*:1:42\n  |\n1 | Product.sortedByPriceLowToHigh() { name, stock }\n  |                                          ^^^^^\n  |",
  ...
}

When unescaped, the response’s summary renders as:

performance_hint: non_covered_document_read - .stock is not covered by the Product.sortedByPriceLowToHigh index. See https://docs.fauna.com/performance_hint/non_covered_document_read.
at *query*:1:42
  |
1 | Product.sortedByPriceLowToHigh() { name, stock }
  |                                          ^^^^^
  |

Query summaries in client drivers

Fauna’s client drivers include summary values in a query info or query response class. This class is used for both successful query responses and errors:

Is this article helpful? 

Tell Fauna how the article can be improved:
Visit Fauna's forums or email docs@fauna.com

Thank you for your feedback!