Subgraph Doctor
Diagnose and fix existing Goldsky Subgraph problems by running CLI commands, reading logs, identifying root causes, and executing fixes.
Boundaries
- Diagnose and fix EXISTING subgraph problems.
- Diagnose only subgraphs that are broken (failing, stalled, erroring, won't deploy). A healthy but slow subgraph is an optimization task — use
/subgraph-builder(e.g. reducing/declaring eth_calls). - Do not build or scaffold new subgraphs — use
/subgraph-builderfor authoring/init/deploy. - Do not handle The Graph migrations — use
/subgraph-migrate. - Do not serve as a command reference — use
/subgraph-builderorgoldsky subgraph <cmd> --helpfor CLI syntax and flag lookups. - Do not handle Turbo or Mirror pipelines — use
/turbo-doctoror/mirror-doctor. - Customer-facing only. Use only
goldskyCLI commands, the dashboard, and GraphQL queries. Never suggestgraphman,kubectl, Datadog, or direct database access — those are internal Goldsky tooling. When a problem needs them, escalate to support (see Step 6).
Mode Detection
Before running anything, check if you have the Bash tool:
- Bash available (CLI mode): Run commands directly and parse output.
- Bash NOT available (reference mode): Give the user one command at a time, explain what to look for, and proceed based on what they paste back.
Diagnostic Workflow
Follow these steps in order. Each builds on the previous one.
Step 1: Verify Authentication
Run goldsky project list 2>&1 to confirm the user is logged in.
- If logged in: Note the project name and continue.
- If not logged in: Direct the user to
/auth-setup. Do not proceed until auth works.
Step 2: Identify the Subgraph
Run goldsky subgraph list 2>&1 to list all subgraphs and their status.
If the user already named a subgraph (name/version), confirm it exists in the list. Otherwise show the list and ask which one to diagnose. Note its status and which network it indexes — a wrong network is one of the most common root causes (see Step 5).
Step 3: Triage by Symptom
Subgraph problems fall into a few families. Pick the path that matches the symptom:
| Symptom | Likely family | Go to |
|---|---|---|
| Deploy command failed (never created) | Deploy-time error | Step 4 → "Deploy-time failures" |
| Stuck at a block / head not moving / stalled / auto-paused | Indexing stalled | Step 4 → logs + _meta |
Error / failed health, indexing halted |
Handler/mapping error | Step 4 → logs |
| Stuck at low % during a migration | Sync-from-scratch (slow), or handler error | Step 4 → logs + _meta |
| Endpoint 404 / no data / can't query | Endpoint or not-yet-synced | Step 4 → _meta + endpoint check |
reached the subgraph limit, database unavailable, frozen with no log errors |
Operational/quota (Goldsky-side) | Step 6 (escalate) |
Step 4: Gather Diagnostic Data
Run these and analyze before concluding:
# Errors only — START HERE. Widen the window (e.g. --since 24h) if nothing shows.
goldsky subgraph log <name/version> --since 1h --filter error 2>&1
# Subgraph + tag + deployment status
goldsky subgraph list <name/version> 2>&1
Do not pull unfiltered logs. Subgraphs emit a huge volume at
info/debuglevel — runninggoldsky subgraph logwithout--filter erroris slow and extremely token-hungry, and rarely adds signal over the error-filtered view. If you genuinely need non-error context, scope it tightly: a very short window (--since 5m) and, if possible, grep for a specific string. Lead with errors + the_metaquery below.
Then run the _meta query against the GraphQL endpoint — this is the single most useful check for "stuck" or "no data" subgraphs. It reports the latest indexed block:
{
_meta {
deployment
hasIndexingErrors
block { number hash timestamp }
}
}
hasIndexingErrors: true→ a handler/mapping error halted indexing. Go to the error patterns below.block.numberfar behind the chain head → still syncing (or stalled). Compare against a block explorer.block.numberahead of / not yet on the chain → wrong network deployed (see below).
Step 5: Match Error Patterns
Wrong network / contract on the wrong chain
Symptoms: Subgraph never produces data, or _meta shows a start/current block that doesn't exist yet on the target chain. Often the subgraph name hints at the intended chain.
Cause: The manifest's network/chain slug points at a different chain than intended, so the subgraph is waiting for blocks that haven't been mined.
Fix: Correct the network in subgraph.yaml (verify the exact chain slug against the supported-networks docs at docs.goldsky.com/chains/supported-networks — e.g. it's liteforge, not litvm-testnet) and redeploy a new version. Confirm the contract address actually exists on the target chain via a block explorer.
Deploy-time failures
The deploy command errors out and nothing gets created. Common cases:
| Error / symptom | Cause | Fix |
|---|---|---|
no network <slug> found |
Wrong/unknown chain slug in subgraph.yaml |
Use the correct slug from supported networks. |
YAML parse error from subgraph init |
Illegal characters in --contract-name (e.g. :, spaces from an explorer label) |
Pass a clean name: --contract-name PolymarketUMACTFAdapter. |
subgraph must use a single apiVersion across its data sources. Found: 0.0.7, 0.0.9 |
Mixed apiVersion across dataSources/templates |
Unify apiVersion across the whole manifest. |
Interface '<X>' not defined |
Schema references an undefined interface | Define the interface in schema.graphql. |
Timeseries/aggregation spec errors (must have id field of type Int8, @unique missing, aggregations not supported in spec version 1.0.0) |
Schema uses timeseries/aggregations not valid for the spec version | Fix the id type to Int8, add @unique, or remove aggregations. |
A deployment with this name & version already exists |
Re-deploying the same name/version |
Bump the version, or goldsky subgraph delete <name/version> then redeploy. |
| `curl ... | sh` install fails (Windows) | Install script is shell-only |
Handler / mapping errors (indexing halts)
Symptoms: hasIndexingErrors: true; logs show things like:
Mapping aborted at src/mappings/...: unexpected null in handler '<handler>' at block #<n>Subgraph error ... code: SubgraphSyncingFailureToken.loadfailures / Heap (out-of-memory) errors- WASM trap / "Handler skipped due to execution failure" (when
nonFatalErrorsis enabled)
Cause: A bug in the customer's AssemblyScript mappings — most often a null dereference. Classic case: an entity is never .save()d because the handler early-returns when a token's decimals()/symbol() reverts (non-ERC-20 contract), then a later handler .load()s that missing entity and panics.
Fix:
- Identify the handler and block from the error.
- Patch the mapping so it doesn't skip
.save()on the null path (e.g. defaultdecimalsto a sentinel like18, persist the entity, skip downstream pricing). - Redeploy a new version and rewind to the first affected block so the missing entities re-initialize.
- As a stopgap to keep the endpoint serving (incomplete) data while you fix it,
subgraphError: allowlets queries return partial results.
Goldsky-side caveat: a deterministic error with
nonFatalErrorsenabled may not auto-clear even after the underlying cause is resolved. If a subgraph stays errored after a correct redeploy, escalate (Step 6).
Stalled / auto-paused subgraph
Symptoms: Head stops advancing; Goldsky auto-pauses a stalled subgraph and emails you.
Cause: Often a handler error (above), sometimes a transient upstream RPC issue or a stale source chain.
Fix:
- Check logs and
_metafor errors first. - If it's a code bug, fix and redeploy. If it was transient, resume:
goldsky subgraph start <name/version>. - If the source chain itself is stale (no new blocks on the explorer either), there's nothing to index — wait for the chain.
Upstream RPC errors
Symptoms: eth_getLogs does not exist / method-not-supported, or Found no transaction for event / block-number mismatches.
Cause: The chain's RPC provider is misbehaving or missing methods — not the subgraph. (Real case: a node stamped every log with the request's fromBlock, so graph-node couldn't match logs to blocks and went fatal.)
Fix: This is Goldsky/RPC-side. Confirm it's not a manifest issue, then escalate (Step 6) with the exact error and block number.
Endpoint / query problems
Symptoms: 404 on the GraphQL endpoint, "no data", or rate-limit errors.
- 404 / no data: The subgraph may not be synced yet (check
_meta), or the public endpoint is disabled. Verify the endpoint URL withgoldsky subgraph list <name/version>. Don't assume an endpoint is live before the resource exists and has synced. - Public vs private: If queries fail auth, the endpoint may be private. Toggle with
goldsky subgraph update <name/version> --public-endpoint enabled(see/subgraph-builder). - Rate limits: Default is ~50 requests / 10 seconds. Higher limits are sales/support-gated — escalate (Step 6); don't promise a specific new limit.
Step 6: Present Diagnosis
## Diagnosis
**Subgraph:** <name/version>
**Network:** <chain>
**Symptom:** <one-line>
**Root cause:**
<what's wrong and why>
**Evidence:**
- <log line / _meta block number / error string>
**Recommended fix:**
1. <step>
2. <step>
**Prevention:**
<how to avoid it next time, if applicable>
When to escalate to support@goldsky.com (don't burn cycles guessing):
- Operational/quota issues not visible via CLI:
reached the subgraph limit(especially if the count looks wrong),database unavailable, frozen head with no log errors. - Upstream RPC bugs (
eth_getLogs does not exist, log/block mismatches). - A subgraph that stays errored after a verified-correct redeploy.
Give the user the exact info to send: subgraph name/version, project ID, the GraphQL endpoint, the error string, and the affected block number. Mention they can reference using the AI/MCP for priority handling.
Step 7: Execute Fix
Offer to run fixes, and confirm before anything destructive:
- Resume a paused subgraph:
goldsky subgraph start <name/version> - Pause for maintenance:
goldsky subgraph pause <name/version> - Redeploy a fixed version:
goldsky subgraph deploy <name/new-version> --path . - Redeploy with a rewind:
goldsky subgraph deploy <name/version> --start-block <firstAffectedBlock> - Delete and recreate (last resort, reindexes from scratch — warn the user):
goldsky subgraph delete <name/version>then redeploy.
After a fix, re-check goldsky subgraph list <name/version> and the _meta query to confirm the head is advancing again.
Common mapping-code root causes (catch before redeploy)
When indexing halted on a handler/mapping error, the underlying cause is almost always one of these AssemblyScript mistakes. Check the mapping for them before redeploying — and recommend the Subgraph Linter (static analysis) plus Matchstick tests so they never reach a deploy again (see /subgraph-builder → references/testing.md):
| Root cause | Symptom it produces | Fix |
|---|---|---|
Unchecked Entity.load(id)! force-unwrap |
unexpected null in handler panic when the entity is missing |
Use get-or-create; never !-unwrap a load. |
Early-return that skips .save() (often after a reverting decimals()/symbol() on a non-ERC-20) |
later .load() panics; Token.load/Heap errors |
Use try_ calls, default the value, persist the entity, skip only downstream pricing. |
| Division without a zero guard | math abort / unexpected null |
Wrap in a safeDiv (return 0 when denominator is 0). |
Stale .save() after a helper already mutated the entity |
overwritten/clobbered fields, wrong data (not always a crash) | Load once, mutate, save once; don't save a stale copy. |
Per-event eth_call that reverts or is undeclared |
slow indexing or unexpected null |
Make it revert-safe (try_) and declare it (specVersion 1.2.0+). |
These are the causes behind the reactive symptoms in Step 5's "Handler / mapping errors". Fixing the code and rewinding to the first affected block is the durable fix.
Important Rules
- Always gather data (logs +
_meta) before diagnosing. Never guess. - "The product is solid — most issues are customer-side." Check the obvious customer causes first (wrong network, mapping bug, schema/manifest error) before assuming a Goldsky-side problem.
- Never recommend
graphman/kubectl/Datadog/database access to a customer. Escalate instead. - Confirm before destructive commands (delete, reindex from scratch).
- Redeploying creates a new immutable version. Use tags so the frontend URL doesn't change (see
/subgraph-builder).
When Bash Is Not Available
Give one command at a time, explain what to look for, and proceed based on the user's pasted output. Always prefer running commands directly when Bash is available.
Related
/subgraph-builder— Build, author, and deploy subgraphs; schema/mapping/manifest authoring; endpoints, tags, webhooks/subgraph-migrate— Migrate a subgraph from The Graph/auth-setup— CLI installation and authentication/datasets— Chain prefixes and supported-network slugs/turbo-doctor,/mirror-doctor— Pipeline (not subgraph) diagnosis