Skip to content

Commit 79144c1

Browse files
author
eugenia
committed
docs: add subgraph linter guide
1 parent b08bb39 commit 79144c1

File tree

2 files changed

+150
-0
lines changed

2 files changed

+150
-0
lines changed

website/src/pages/en/subgraphs/guides/_meta.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ export default {
33
'subgraph-debug-forking': '',
44
near: '',
55
grafting: '',
6+
'subgraph-linter': '',
67
'subgraph-uncrashable': '',
78
'transfer-to-the-graph': '',
89
enums: '',
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
---
2+
title: Subgraph Linter
3+
sidebarTitle: Static Analysis with Subgraph Linter
4+
---
5+
6+
[Subgraph Linter](https://github.com/graphops/subgraph-linter) is a static analysis tool for The Graph subgraphs. It analyzes your subgraph code before deployment and surfaces common patterns that lead to runtime crashes, corrupted entity state, silent data errors, or unnecessary performance overhead.
7+
8+
Instead of discovering issues after deploying and indexing (or worse, after production failures), Subgraph Linter complements existing tooling to help you catch problems locally while you write code. It does not replace testing (either runtime or via unit tests), but it can dramatically reduce the class of bugs that ever make it to production deployments.
9+
10+
## Why run Subgraph Linter?
11+
12+
Subgraph handlers often fail in subtle ways that don’t show up until indexing starts:
13+
14+
- Entities are saved with missing required fields
15+
- Multiple instances of the same entity handled at the same time causing overwrite issues
16+
- Optional values are force-unwrapped without checks
17+
- Divisions happen without proving the divisor is non-zero
18+
- Derived fields are mutated directly or left stale
19+
- Contract calls are made without being declared in the manifest
20+
21+
These bugs usually compile fine, but crash at runtime or silently produce incorrect data. Subgraph Linter performs static analysis on your mapping code to detect these issues before deploying the subgraph.
22+
23+
## How it works
24+
25+
Subgraph Linter analyzes your subgraph manifest and the mapping files referenced by it. It understands how Graph mappings are typically structured and tracks things such as:
26+
27+
- Entity identity (type + id)
28+
- Loads, saves, and reloads
29+
- Helper call graphs (including nested helpers)
30+
- Assignments and mutations
31+
- Control flow guards (null checks, zero checks, short-circuit logic)
32+
33+
From this, it applies a set of targeted checks designed specifically for problematic subgraph code patterns.
34+
35+
## Key checks
36+
37+
Subgraph Linter currently detects the following categories of issues:
38+
39+
- `entity-overwrite`: Detects cases where a handler works with an entity instance that becomes stale after calling a helper (or other code path) that loads and saves the same entity, and then the handler saves its stale instance and overwrites those updates.
40+
- `unexpected-null`: Detects when entities may be saved in an invalid state—either because required fields weren’t initialized before `save()`, or because code attempts to assign to `@derivedFrom` fields.
41+
- `unchecked-load`: Detects risky patterns where `Entity.load(...)` is treated as always present (for example via `!`) instead of explicitly handling the case where the entity doesn’t exist yet.
42+
- `unchecked-nonnull`: Detects risky non-null assertions on values that can be missing at runtime, and encourages explicit guards instead of assuming the value is always set.
43+
- `division-guard`: Detects divisions where the denominator may be zero on some execution paths, and suggests guarding the value before dividing.
44+
- `derived-field-guard`: Detects cases where code updates “base” fields that require derived recomputation, but then saves without the helper(s) that keep derived values consistent.
45+
- `helper-return-contract`: Detects helper functions that can return entities without fully initializing required fields, and flags call sites where the returned entity is used/saved without completing initialization.
46+
- `undeclared-eth-call`: Detects contract calls made by a handler (including inside helpers it calls) that are not declared in the handler’s `calls:` block in `subgraph.yaml`, so you can add the declaration and align with Graph’s declared `eth_call` best practices.
47+
48+
## Using Subgraph Linter
49+
50+
The tool can be run in two ways:
51+
52+
- As a CLI, suitable for local use or CI pipelines
53+
- As a VS Code extension, using an LSP server to highlight issues inline as you code
54+
55+
### Using Subgraph Linter as CLI
56+
57+
Build the linter locally:
58+
59+
```bash
60+
cd subgraph-linter
61+
npm install
62+
npm run build
63+
```
64+
65+
Run it against a subgraph manifest:
66+
67+
```bash
68+
npm run check -- --manifest ../your-subgraph/subgraph.yaml
69+
```
70+
71+
If your repository uses a non-standard TypeScript setup, you can specify a `tsconfig.json`:
72+
73+
```bash
74+
npm run check -- --manifest ../your-subgraph/subgraph.yaml --tsconfig ../your-subgraph/tsconfig.json
75+
```
76+
77+
You can also provide an explicit config file:
78+
79+
```bash
80+
npm run check -- --manifest ../your-subgraph/subgraph.yaml --config ./subgraph-linter.config.json
81+
```
82+
83+
*Configuration note:* Subgraph Linter supports configurable severities per check. By default, checks have sensible severities, but you can override them to match your project’s tolerance. Only checks with effective severity `error` cause a non-zero exit code; warnings-only runs exit successfully.
84+
85+
### Configuration (severity overrides and suppression)
86+
87+
Subgraph Linter reads configuration from `subgraph-linter.config.json` (or the file passed via `--config`).
88+
89+
The two main configuration features are:
90+
91+
1. **Severity overrides** (treat certain checks as warnings or errors)
92+
2. **Comment-based suppression** (allow silencing diagnostics in exceptional cases)
93+
94+
Example:
95+
96+
```json
97+
{
98+
"severityOverrides": {
99+
"division-guard": "error",
100+
"undeclared-eth-call": "warning"
101+
},
102+
"suppression": {
103+
"allowWarnings": true,
104+
"allowErrors": true
105+
}
106+
}
107+
```
108+
109+
### Suppressing a warning or error with a comment
110+
111+
In some cases, the linter may not be able to prove that a pattern is safe, but you may know it’s safe due to domain knowledge. In those cases, you can suppress a specific check on a specific line with:
112+
113+
```tsx
114+
// [allow(derived-field-guard)]
115+
graphNetwork.save()
116+
```
117+
118+
You can also suppress everything for a line using `// [allow(all)]`.
119+
120+
### Using Subgraph Linter in VS Code
121+
122+
The VS Code extension runs a diagnostics-only language server and shows Subgraph Linter results in the editor and the Problems panel.
123+
124+
What to expect:
125+
126+
- The extension auto-discovers `subgraph.yaml` files in your workspace (skipping `build/` and `dist/`).
127+
- If multiple manifests are found, it prompts you to select one and remembers the selection.
128+
- It runs on save by default (configurable).
129+
130+
Commands:
131+
132+
- **Subgraph Linter: Run Analysis** (`subgraph-linter.runAnalysis`)
133+
- **Subgraph Linter: Add Call Declaration** (`subgraph-linter.addCallDeclaration`)
134+
Offered as a quick fix for `undeclared-eth-call` diagnostics when a declaration can be generated.
135+
- **Suppress `<check-id>` on this line**
136+
Offered as a quick fix for Subgraph Linter diagnostics; inserts `// [allow(<check-id>)]`.
137+
138+
Settings (prefix `subgraphLinter`):
139+
140+
- `manifestPaths`: override manifest auto-discovery with explicit paths
141+
- `tsconfigPath`: pass an explicit `tsconfig.json` path to the analyzer
142+
- `configPath`: pass an explicit linter config path
143+
- `runOnSave`: run analysis when files are saved (default `true`)
144+
145+
## Extending the linter
146+
147+
Subgraph Linter is designed to grow as new subgraph failure patterns are discovered.
148+
149+
See [ADDING_CHECKS.md](https://github.com/graphops/subgraph-linter/blob/main/ADDING_CHECKS.md) in the repository for a step-by-step guide.

0 commit comments

Comments
 (0)