From bdaf6ac5c0704f9b7f05fb93b7ffcacd834094cf Mon Sep 17 00:00:00 2001 From: eugenia Date: Mon, 22 Dec 2025 16:08:01 -0300 Subject: [PATCH 1/8] docs: add subgraph linter guide --- .../src/pages/en/subgraphs/guides/_meta.js | 1 + .../en/subgraphs/guides/subgraph-linter.mdx | 149 ++++++++++++++++++ 2 files changed, 150 insertions(+) create mode 100644 website/src/pages/en/subgraphs/guides/subgraph-linter.mdx diff --git a/website/src/pages/en/subgraphs/guides/_meta.js b/website/src/pages/en/subgraphs/guides/_meta.js index 1c081848ea08..07c6de9c95bc 100644 --- a/website/src/pages/en/subgraphs/guides/_meta.js +++ b/website/src/pages/en/subgraphs/guides/_meta.js @@ -3,6 +3,7 @@ export default { 'subgraph-debug-forking': '', near: '', grafting: '', + 'subgraph-linter': '', 'subgraph-uncrashable': '', 'transfer-to-the-graph': '', enums: '', diff --git a/website/src/pages/en/subgraphs/guides/subgraph-linter.mdx b/website/src/pages/en/subgraphs/guides/subgraph-linter.mdx new file mode 100644 index 000000000000..56dc74d996a3 --- /dev/null +++ b/website/src/pages/en/subgraphs/guides/subgraph-linter.mdx @@ -0,0 +1,149 @@ +--- +title: Subgraph Linter +sidebarTitle: Static Analysis with Subgraph Linter +--- + +[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. + +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. + +## Why run Subgraph Linter? + +Subgraph handlers often fail in subtle ways that don’t show up until indexing starts: + +- Entities are saved with missing required fields +- Multiple instances of the same entity handled at the same time causing overwrite issues +- Optional values are force-unwrapped without checks +- Divisions happen without proving the divisor is non-zero +- Derived fields are mutated directly or left stale +- Contract calls are made without being declared in the manifest + +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. + +## How it works + +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: + +- Entity identity (type + id) +- Loads, saves, and reloads +- Helper call graphs (including nested helpers) +- Assignments and mutations +- Control flow guards (null checks, zero checks, short-circuit logic) + +From this, it applies a set of targeted checks designed specifically for problematic subgraph code patterns. + +## Key checks + +Subgraph Linter currently detects the following categories of issues: + +- `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. +- `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. +- `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. +- `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. +- `division-guard`: Detects divisions where the denominator may be zero on some execution paths, and suggests guarding the value before dividing. +- `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. +- `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. +- `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. + +## Using Subgraph Linter + +The tool can be run in two ways: + +- As a CLI, suitable for local use or CI pipelines +- As a VS Code extension, using an LSP server to highlight issues inline as you code + +### Using Subgraph Linter as CLI + +Build the linter locally: + +```bash +cd subgraph-linter +npm install +npm run build +``` + +Run it against a subgraph manifest: + +```bash +npm run check -- --manifest ../your-subgraph/subgraph.yaml +``` + +If your repository uses a non-standard TypeScript setup, you can specify a `tsconfig.json`: + +```bash +npm run check -- --manifest ../your-subgraph/subgraph.yaml --tsconfig ../your-subgraph/tsconfig.json +``` + +You can also provide an explicit config file: + +```bash +npm run check -- --manifest ../your-subgraph/subgraph.yaml --config ./subgraph-linter.config.json +``` + +*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. + +### Configuration (severity overrides and suppression) + +Subgraph Linter reads configuration from `subgraph-linter.config.json` (or the file passed via `--config`). + +The two main configuration features are: + +1. **Severity overrides** (treat certain checks as warnings or errors) +2. **Comment-based suppression** (allow silencing diagnostics in exceptional cases) + +Example: + +```json +{ + "severityOverrides": { + "division-guard": "error", + "undeclared-eth-call": "warning" + }, + "suppression": { + "allowWarnings": true, + "allowErrors": true + } +} +``` + +### Suppressing a warning or error with a comment + +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: + +```tsx +// [allow(derived-field-guard)] +graphNetwork.save() +``` + +You can also suppress everything for a line using `// [allow(all)]`. + +### Using Subgraph Linter in VS Code + +The VS Code extension runs a diagnostics-only language server and shows Subgraph Linter results in the editor and the Problems panel. + +What to expect: + +- The extension auto-discovers `subgraph.yaml` files in your workspace (skipping `build/` and `dist/`). +- If multiple manifests are found, it prompts you to select one and remembers the selection. +- It runs on save by default (configurable). + +Commands: + +- **Subgraph Linter: Run Analysis** (`subgraph-linter.runAnalysis`) +- **Subgraph Linter: Add Call Declaration** (`subgraph-linter.addCallDeclaration`) + Offered as a quick fix for `undeclared-eth-call` diagnostics when a declaration can be generated. +- **Suppress `` on this line** + Offered as a quick fix for Subgraph Linter diagnostics; inserts `// [allow()]`. + +Settings (prefix `subgraphLinter`): + +- `manifestPaths`: override manifest auto-discovery with explicit paths +- `tsconfigPath`: pass an explicit `tsconfig.json` path to the analyzer +- `configPath`: pass an explicit linter config path +- `runOnSave`: run analysis when files are saved (default `true`) + +## Extending the linter + +Subgraph Linter is designed to grow as new subgraph failure patterns are discovered. + +See [ADDING_CHECKS.md](https://github.com/graphops/subgraph-linter/blob/main/ADDING_CHECKS.md) in the repository for a step-by-step guide. From 0dfa8c5caaea9f8f483d18cdb190a8975c7fb821 Mon Sep 17 00:00:00 2001 From: eugenia <153332549+eugeniatel@users.noreply.github.com> Date: Tue, 13 Jan 2026 09:35:27 -0300 Subject: [PATCH 2/8] Update website/src/pages/en/subgraphs/guides/subgraph-linter.mdx Co-authored-by: Idalith <126833353+idalithb@users.noreply.github.com> --- website/src/pages/en/subgraphs/guides/subgraph-linter.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/src/pages/en/subgraphs/guides/subgraph-linter.mdx b/website/src/pages/en/subgraphs/guides/subgraph-linter.mdx index 56dc74d996a3..257c3caadf2f 100644 --- a/website/src/pages/en/subgraphs/guides/subgraph-linter.mdx +++ b/website/src/pages/en/subgraphs/guides/subgraph-linter.mdx @@ -5,7 +5,7 @@ sidebarTitle: Static Analysis with Subgraph Linter [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. -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. +It complements existing tools by helping you catch problems locally while writing code, rather than discovering them after deployment or in production. It does not replace testing (runtime or unit tests), but it can reduce the number of bugs that make it to production. ## Why run Subgraph Linter? From f36519c267270c17138ac8f8e820b32cc3aa82d1 Mon Sep 17 00:00:00 2001 From: eugenia <153332549+eugeniatel@users.noreply.github.com> Date: Tue, 13 Jan 2026 09:35:41 -0300 Subject: [PATCH 3/8] Update website/src/pages/en/subgraphs/guides/subgraph-linter.mdx Co-authored-by: Idalith <126833353+idalithb@users.noreply.github.com> --- website/src/pages/en/subgraphs/guides/subgraph-linter.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/src/pages/en/subgraphs/guides/subgraph-linter.mdx b/website/src/pages/en/subgraphs/guides/subgraph-linter.mdx index 257c3caadf2f..dfd3f5884ad4 100644 --- a/website/src/pages/en/subgraphs/guides/subgraph-linter.mdx +++ b/website/src/pages/en/subgraphs/guides/subgraph-linter.mdx @@ -7,7 +7,7 @@ sidebarTitle: Static Analysis with Subgraph Linter It complements existing tools by helping you catch problems locally while writing code, rather than discovering them after deployment or in production. It does not replace testing (runtime or unit tests), but it can reduce the number of bugs that make it to production. -## Why run Subgraph Linter? +## When to use it Subgraph handlers often fail in subtle ways that don’t show up until indexing starts: From b0f02acef818147d289a0d2891ad8926e8e4d853 Mon Sep 17 00:00:00 2001 From: eugenia <153332549+eugeniatel@users.noreply.github.com> Date: Tue, 13 Jan 2026 09:36:03 -0300 Subject: [PATCH 4/8] Update website/src/pages/en/subgraphs/guides/subgraph-linter.mdx Co-authored-by: Idalith <126833353+idalithb@users.noreply.github.com> --- website/src/pages/en/subgraphs/guides/subgraph-linter.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/src/pages/en/subgraphs/guides/subgraph-linter.mdx b/website/src/pages/en/subgraphs/guides/subgraph-linter.mdx index dfd3f5884ad4..1b9767370637 100644 --- a/website/src/pages/en/subgraphs/guides/subgraph-linter.mdx +++ b/website/src/pages/en/subgraphs/guides/subgraph-linter.mdx @@ -9,7 +9,7 @@ It complements existing tools by helping you catch problems locally while writin ## When to use it -Subgraph handlers often fail in subtle ways that don’t show up until indexing starts: +Run Subgraph Linter when you want to detect handler and mapping issues that don't often appear until indexing starts, such as: - Entities are saved with missing required fields - Multiple instances of the same entity handled at the same time causing overwrite issues From ec9c1d4e9978b134891a58ff70636249241b759c Mon Sep 17 00:00:00 2001 From: eugenia <153332549+eugeniatel@users.noreply.github.com> Date: Tue, 13 Jan 2026 09:36:30 -0300 Subject: [PATCH 5/8] Update website/src/pages/en/subgraphs/guides/subgraph-linter.mdx Co-authored-by: Idalith <126833353+idalithb@users.noreply.github.com> --- .../pages/en/subgraphs/guides/subgraph-linter.mdx | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/website/src/pages/en/subgraphs/guides/subgraph-linter.mdx b/website/src/pages/en/subgraphs/guides/subgraph-linter.mdx index 1b9767370637..ba89b642e7b5 100644 --- a/website/src/pages/en/subgraphs/guides/subgraph-linter.mdx +++ b/website/src/pages/en/subgraphs/guides/subgraph-linter.mdx @@ -11,13 +11,12 @@ It complements existing tools by helping you catch problems locally while writin Run Subgraph Linter when you want to detect handler and mapping issues that don't often appear until indexing starts, such as: -- Entities are saved with missing required fields -- Multiple instances of the same entity handled at the same time causing overwrite issues -- Optional values are force-unwrapped without checks -- Divisions happen without proving the divisor is non-zero -- Derived fields are mutated directly or left stale -- Contract calls are made without being declared in the manifest - +- Entities saved with missing required fields +- Entity overwrite issues from concurrent/stale instances +- Optional values force-unwrapped without checks +- Divisions without guaranteeing a non-zero denominator +- `@derivedFrom` fields mutated directly or left stale +- Contract calls are used without being declared in the manifest 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. ## How it works From 14fd69f2b2bb386440727cc2b55b9d3bf951a191 Mon Sep 17 00:00:00 2001 From: eugenia <153332549+eugeniatel@users.noreply.github.com> Date: Tue, 13 Jan 2026 09:37:19 -0300 Subject: [PATCH 6/8] Update website/src/pages/en/subgraphs/guides/subgraph-linter.mdx Co-authored-by: Idalith <126833353+idalithb@users.noreply.github.com> --- website/src/pages/en/subgraphs/guides/subgraph-linter.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/src/pages/en/subgraphs/guides/subgraph-linter.mdx b/website/src/pages/en/subgraphs/guides/subgraph-linter.mdx index ba89b642e7b5..74a6bbbb3ddc 100644 --- a/website/src/pages/en/subgraphs/guides/subgraph-linter.mdx +++ b/website/src/pages/en/subgraphs/guides/subgraph-linter.mdx @@ -81,7 +81,7 @@ npm run check -- --manifest ../your-subgraph/subgraph.yaml --config ./subgraph-l *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. -### Configuration (severity overrides and suppression) +#### Configuration (severity overrides and suppression) Subgraph Linter reads configuration from `subgraph-linter.config.json` (or the file passed via `--config`). From 8a2ae575944ace5c931d2f56bec4801766d23e99 Mon Sep 17 00:00:00 2001 From: eugenia <153332549+eugeniatel@users.noreply.github.com> Date: Tue, 13 Jan 2026 09:37:55 -0300 Subject: [PATCH 7/8] Update website/src/pages/en/subgraphs/guides/subgraph-linter.mdx Co-authored-by: Idalith <126833353+idalithb@users.noreply.github.com> --- website/src/pages/en/subgraphs/guides/subgraph-linter.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/src/pages/en/subgraphs/guides/subgraph-linter.mdx b/website/src/pages/en/subgraphs/guides/subgraph-linter.mdx index 74a6bbbb3ddc..d42a662b032d 100644 --- a/website/src/pages/en/subgraphs/guides/subgraph-linter.mdx +++ b/website/src/pages/en/subgraphs/guides/subgraph-linter.mdx @@ -105,7 +105,7 @@ Example: } ``` -### Suppressing a warning or error with a comment +#### Suppressing a warning or error with a comment 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: From 104ba5564d63b2dee7921becb075ad848c05bc80 Mon Sep 17 00:00:00 2001 From: eugenia Date: Tue, 13 Jan 2026 11:23:32 -0300 Subject: [PATCH 8/8] docs: clarify configuration motivation --- website/src/pages/en/subgraphs/guides/subgraph-linter.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/src/pages/en/subgraphs/guides/subgraph-linter.mdx b/website/src/pages/en/subgraphs/guides/subgraph-linter.mdx index d42a662b032d..b71f76af1e4d 100644 --- a/website/src/pages/en/subgraphs/guides/subgraph-linter.mdx +++ b/website/src/pages/en/subgraphs/guides/subgraph-linter.mdx @@ -83,7 +83,7 @@ npm run check -- --manifest ../your-subgraph/subgraph.yaml --config ./subgraph-l #### Configuration (severity overrides and suppression) -Subgraph Linter reads configuration from `subgraph-linter.config.json` (or the file passed via `--config`). +Configuration lets teams apply the project-specific severities and tolerances described above. Subgraph Linter reads configuration from `subgraph-linter.config.json` (or the file passed via `--config`). The two main configuration features are: