Skip to content

Conversation

@eugeniatel
Copy link

Adds a new guide documenting Subgraph Linter, a static analysis tool for subgraphs.

Includes:

  • Overview / why use Subgraph Linter
  • Common failure patterns it detects
  • Integration into development

@eugeniatel eugeniatel requested a review from a team as a code owner December 22, 2025 20:12
Copy link
Contributor

@idalithb idalithb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please review suggested changes, but I've approved 😄

Comment on lines +23 to +46
## 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.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This whole section might work after the tutorial
Devs usually want the "how-to" right away

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I personally think it's fine either way, but I don't have a lot of knowledge about other devs preferences, nor did I work on lots of docs, so I'll leave it for others to decide 😅

Comment on lines 85 to 92
### 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)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They might want to first know why they might want to use this (but if I'm wrong diregard)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's quite common for linters to be able to be supressed (maybe the linter is flagging something you know for certain isn't an issue, and don't want to have it flagged in your CLI/VSCode), so I'd say it's almost self explanatory, but I might be wrong

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants