DevTools, logs and Altair as a debugging stack
When a Magento page fails to load or shows wrong data, the problem often lies in a GraphQL query, but where exactly? Browser DevTools, Magento logs and dedicated GraphQL clients form the complete debugging stack.
Table of Contents
- 1. The debugging workflow at a glance
- 2. Chrome Network tab: finding and inspecting GraphQL requests
- 3. Analyzing the query payload and response
- 4. Understanding Magento-specific headers
- 5. Altair: reproducing a query from the browser
- 6. Magento logs: evaluating system.log and exception.log
- 7. Using Xdebug in resolver methods
- 8. Debugging tools compared
- 9. Summary
- 10. The most important points at a glance
- 11. FAQ
1. The debugging workflow at a glance
For Magento issues related to GraphQL, there is a clear debugging workflow that leads from the browser interface all the way to the resolver code. The first step is always observation in the browser: which requests are triggered, which status codes come back, which errors appear in the response body. The second step is reproducing the query in a dedicated GraphQL client such as Altair, to eliminate the browser context and examine the query in isolation. The third step is log analysis on the server, to find resolver errors that appear in the browser response only as a generic error message. The fourth step, if needed, is Xdebug in the resolver code itself.
This workflow applies both to Hyvä frontends and to classic Magento Luma themes that use GraphQL. In Hyvä, GraphQL requests are sent directly from Alpine.js components, often via fetch in the template, which makes them especially easy to find in the Network tab, since they appear as regular POST requests to /graphql. For React- or Vue-based headless frontends it is identical: all GraphQL requests land on a single endpoint, which simplifies filtering in the Network tab.
2. Chrome Network tab: finding and inspecting GraphQL requests
In the Chrome DevTools Network tab, GraphQL requests are easiest to find using the filter graphql in the search bar, Chrome filters for all requests whose URL contains the word "graphql". Alternatively, filter by Method: POST, since GraphQL queries are always sent as POST requests. Modern Chrome versions also have a dedicated "Payload" tab that displays JSON-formatted request bodies clearly, including the query field, the operationName and the variables.
Especially useful for timing analysis in the Network tab is the "Waterfall" column: it shows how much time a GraphQL request spends in various phases. A long TTFB (Time to First Byte) points to slow server-side processing, usually slow resolvers or missing caches. A short TTFB but a long transfer time points to an oversized response payload. This distinction helps to clearly assign the cause to one of the two sides before switching to logs or code.
# Query payload visible in the Chrome Network tab
# Copied from the "Payload" tab of a /graphql POST request
# The "query" field contains the actual GraphQL operation:
# {
# "operationName": "GetCategoryProducts",
# "variables": {
# "categoryId": "15",
# "pageSize": 12,
# "currentPage": 1,
# "sort": { "position": "ASC" }
# },
# "query": "..."
# }
query GetCategoryProducts(
$categoryId: String!
$pageSize: Int = 12
$currentPage: Int = 1
$sort: ProductAttributeSortInput
) {
products(
filter: { category_id: { eq: $categoryId } }
pageSize: $pageSize
currentPage: $currentPage
sort: $sort
) {
total_count
page_info { current_page total_pages }
items {
__typename
sku
name
url_key
small_image { url label }
price_range {
minimum_price {
final_price { value currency }
}
}
}
}
}
3. Analyzing the query payload and response
Response analysis in the Network tab starts with the HTTP status. GraphQL almost always returns HTTP 200, even on errors. Only fully invalid requests (no JSON, missing query parameter) produce 400 errors. The response body reveals the actual state of things: an errors array in the response signals GraphQL errors, which can exist alongside data. An empty data field for a query that should return data, combined with a populated errors array, is the most common failure pattern.
For detailed response analysis, the "JSON Viewer" Chrome extension or simply opening the response in its own tab is recommended. For large responses, product lists with many fields, keeping an overview in the browser becomes difficult. Here it helps to copy the entire response into a JSON beautifier, or directly into Altair, where the response is displayed in a structured way and can be compared against the schema. Especially helpful: the extensions field in the Magento GraphQL response can contain tracing information when developerMode is active or the tracing plugin has been enabled.
4. Understanding Magento-specific headers
Magento GraphQL requests carry several specific request headers that influence the behavior of the API and are relevant when debugging. The Store header specifies the store code (Store: de) and determines which Magento store, with which language, currency and configuration, responds. If this header is missing or wrong, Magento responds with the default store, which can result in prices in the wrong currency, missing translations, or products in the response that should not exist.
The Authorization header carries the bearer token for authenticated requests. In Hyvä frontends, the token is stored in local storage after login and sent along with every GraphQL request in the header. In the Network tab it is visible in the "Headers" section of the respective request. A missing or expired token on a customer-context query is the most common cause of unexpected authorization errors. The Content-Currency header enables cross-store currency conversion and plays an important role when debugging incorrect price display in multi-currency setups.
# Magento-specific GraphQL headers in the request
# Visible in Chrome DevTools > Network tab > Headers
# Request headers (example):
# POST /graphql HTTP/1.1
# Content-Type: application/json
# Store: de
# Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...
# Content-Currency: EUR
# X-Magento-Cache-Id: abc123def456 (for Varnish/CDN caching)
# Common causes of errors from wrong headers:
# - "Store: default" instead of "Store: de" -> wrong language and prices
# - No Authorization header on a customer.orders query -> 401/empty response
# - Expired bearer token -> extensions.category: "graphql-authorization"
# Response headers to check for caching:
# X-Cache: HIT -> Varnish/Fastly served from cache
# X-Cache: MISS -> query went through to Magento
# Cache-Control: max-age=0, must-revalidate -> not cached (dynamic data)
query CustomerContext {
customer {
firstname
lastname
email
orders(pageSize: 5) {
items {
number
status
order_date
total { grand_total { value currency } }
}
}
}
}
5. Altair: reproducing a query from the browser
Altair GraphQL Client is the preferred tool for reproducing Magento GraphQL queries out of the browser context and debugging them in isolation. The workflow is simple: copy the query and variables from the Chrome Network tab, paste them into Altair, configure the Authorization header and the Store header, and send the request. Altair displays the response in a structured way, validates the query against the schema (provided introspection is active), and lets you conveniently change variables to test different scenarios.
An important step when transferring from the browser into Altair: copy the complete set of request headers, not just the Authorization token. Store header, Currency header and any custom headers for A/B testing or feature flags all need to be carried over, so that Altair sees exactly what the frontend sees. For Magento developers who debug regularly, it is worth saving Altair environments per store view with all required headers, which saves the manual header setup on every debugging session.
6. Magento logs: evaluating system.log and exception.log
When a GraphQL response contains an error whose message is generic ("Internal server error"), the actual cause is in the Magento log. Magento deliberately reduces errors in production configurations to generic messages, to avoid exposing internal details. The exception.log contains the full stack trace of the exception, including file name, line number and the methods called. The system.log contains messages from Magento's logging system, which resolvers write via $this->logger->critical() or $this->logger->error().
In the Mark Shust Docker setup, the log is followed with bin/log exception.log. In developer mode, Magento returns the full error text directly in the GraphQL response, in the errors[].message field, which greatly simplifies debugging. In production, you have to rely on log comparison: note the timestamp of the failed request from the browser's Network tab and search the log for that same timestamp. It also helps to temporarily enable Magento's developerMode on the staging environment, to get complete error messages in the GraphQL response.
# Error analysis: this response structure occurs on resolver exceptions.
# In production: "Internal server error" without details
# In developer mode: full error text in the "message" field
# Example response for a resolver error (developer mode):
# {
# "errors": [
# {
# "message": "No such entity with id = 99999",
# "category": "graphql-no-such-entity",
# "locations": [{ "line": 3, "column": 5 }],
# "path": ["product"]
# }
# ],
# "data": { "product": null }
# }
# Corresponding log entries in var/log/exception.log:
# [2026-05-09 12:34:56] main.CRITICAL: No such entity with id = 99999
# Magento\Catalog\Model\ResourceModel\Product::load()
# ... (stack trace)
# Search the log with: bin/log exception.log | grep "2026-05-09 12:34"
query GetProductById($id: Int!) {
product(id: $id) {
sku
name
price_range {
minimum_price { final_price { value currency } }
}
}
}
7. Using Xdebug in resolver methods
Xdebug in the Magento resolver allows for the deepest level of debugging: step-by-step execution of the resolver code with full access to all variables and the call stack. In the Mark Shust Docker setup, Xdebug is enabled with bin/xdebug enable. Then set a breakpoint in the resolver class, typically in the resolve() method, and trigger the GraphQL request again in the browser or in Altair. PhpStorm receives the debug connection and pauses execution at the breakpoint.
A common problem when using Xdebug with GraphQL: the browser's response timeout setting. GraphQL requests paused by the debugger quickly exceed the browser's 30 to 60 second timeout. Altair is better suited here than the browser, because it has no automatic timeout. Alternatively, bin/debug-cli enable can enable Xdebug for CLI commands, which is useful for GraphQL integration tests in PHPUnit. In deep resolver chains it is also worth setting xdebug.max_nesting_level to a higher value, since Magento resolvers often have deep call hierarchies.
8. Debugging tools compared
Different debugging scenarios call for different tools. The choice depends on whether the error lies in the browser frontend, the network protocol, the Magento resolver, or the data access layer.
| Tool | Strengths | Use case | Limits |
|---|---|---|---|
| Chrome Network tab | Request/response in the real browser context, headers, timing | First-pass analysis, payload copy, timing diagnosis | No schema validation, no query modification |
| Altair GraphQL Client | Schema exploration, query modification, environment management | Reproduction, isolated testing, adjusting variables | No real browser context (cookies, auth flow) |
| Magento exception.log | Full stack trace, PHP-level errors | Resolver exceptions, unhandled errors | No timing, only error events |
| Xdebug + PhpStorm | Step by step, full variable access, watch expressions | Complex resolver logic, hard-to-reproduce errors | Performance overhead, browser timeout issue |
| bin/mysql (query log) | See database queries, spot N+1 patterns in SQL | Performance diagnosis, EAV queries, missing indexes | No direct link to the GraphQL field |
In practice, every debugging session starts with the Chrome Network tab, to identify the failed request and copy the payload. The second step is reproduction in Altair. If an error occurs there, the next step is a look at the exception.log. For hard-to-reproduce errors or complex resolver logic, Xdebug is the last step. The MySQL query log helps additionally when the resolver responds correctly but is nonetheless slow.
9. Summary
Analyzing GraphQL queries in Magento is a multi-stage process from the browser to the resolver code. The Chrome DevTools Network tab delivers the complete request payload, including operation name, variables and headers. Magento-specific headers such as Store and Authorization are decisive for correct API responses. Altair enables isolated reproduction without the browser context, with full schema exploration. Magento logs deliver the full stack trace for generic errors. Xdebug enables step-by-step debugging inside the resolver code itself.
The most important principle: always start with the browser, understand the request, and only then move into the deeper layers. Many Magento GraphQL problems, wrong store headers, expired tokens, missing variables, are already diagnosable at the browser level, without having to open a single log file.
Analyzing GraphQL Queries in Magento: The Most Important Points at a Glance
Network tab first
Chrome DevTools Network tab with the "graphql" filter: request payload, response body, timing and headers visible immediately. First step for every Magento GraphQL problem.
Altair for reproduction
Copy the query, variables and headers from DevTools and reproduce them in Altair, isolated from the browser context, with schema validation and convenient variable editing.
Logs for generic errors
exception.log for stack traces, system.log for resolver logs. In developer mode, Magento returns complete error messages directly in the GraphQL response.
Watch the Magento headers
Store, Authorization and Content-Currency are decisive. A wrong Store header is the most common cause of wrong prices, wrong languages, or empty product lists.