timaub's YAML Lint for Drupal — broken references checker
Your Drupal YAML files point to code that exists: checked while you type, offline, with no PHP and no Drupal install.
Find broken references in *.routing.yml, *.services.yml, *.links.*.yml, *.permissions.yml, *.libraries.yml and *.info.yml before drush cr turns them into a white screen. Read-only. Routes, services, classes and methods are free; permissions, libraries, assets, module dependencies and menu parents are Pro.


Why
A JSON schema (Schema Store, or the free Drupal extension) checks the shape of your YAML: allowed keys, value types. It cannot check that the target exists. That is how these bugs ship:
_controller: '\Drupal\my_module\Controller\ReportControler::build' (typo) → 500 error on the route.
arguments: ['@entity_type.manger'] → "You have requested a non-existent service" and a white screen after drush cr.
route_name: my_module.setings in a menu link → broken admin menu.
timaub's YAML Lint for Drupal indexes your workspace and reports every reference whose target cannot be found, in the Problems panel and inline.
What it checks
| Rule |
Finds |
Default severity |
Edition |
parseError |
YAML file that cannot be parsed |
Error |
Free |
classMissing |
PHP class not found: routing _controller, _form, _title_callback, _custom_access; services class, FQCN service ids, factory; menu links class, deriver |
Error |
Free |
methodMissing |
::method not declared in the class (only when the class has no extends and no trait; otherwise silent) |
Warning |
Free |
serviceMissing |
@service not declared in any *.services.yml: arguments, calls, factory, properties, configurator, parent, decorates, alias, routing _controller: service:method |
Error |
Free |
routeMissing |
Unknown route name: links route_name, local task base_route, local action appears_on, info.yml configure |
Error |
Free |
permissionMissing |
_permission requirement not declared in any *.permissions.yml (+ = OR, , = AND); silent when the route relies on a module absent from the workspace (_module_dependencies, class of that module) |
Warning |
Pro |
libraryMissing |
Unknown library: libraries.yml dependencies, theme libraries, libraries-override, libraries-extend |
Error |
Pro |
assetMissing |
CSS or JS file listed in a library that does not exist on disk (external URLs, scheme:// URIs such as public:// and /libraries/… third-party paths ignored) |
Error |
Pro |
moduleMissing |
Module in info.yml dependencies (or base theme) not in the workspace |
Warning (Information when it belongs to another project that is not installed, e.g. entity_print:entity_print) |
Pro |
linkParentMissing |
Menu link parent or local task parent_id not declared |
Warning |
Pro |
Class resolution follows PSR-4: Drupal\my_module\Form\SettingsForm → <my_module dir>/src/Form/SettingsForm.php, which must declare class SettingsForm (or interface, trait, enum). Drupal\Core\… and Drupal\Component\… resolve under core/lib/Drupal/.
What it does NOT do
No false positive is better than full coverage. A check stays silent when its target cannot be indexed:
- Module not in the workspace. A reference to
@entity_type.manager, system.admin or Drupal\node\… is only checked if the owning module (<name>.info.yml) is in the workspace. Open a single custom module and you get no noise about core or contrib.
- No Drupal core.
Drupal\Core\… classes are checked only if core/lib/Drupal/ is present. permissionMissing and drupal: module dependencies need the Drupal root (core/core.services.yml) in the workspace. Symfony, Psr and other namespaces are never checked.
- Dynamic routes, services and permissions. A module with
route_callbacks, a route subscriber (src/Routing/*Subscriber.php or *Routes.php), a ServiceProvider, or permission_callbacks (for the usual dynamic patterns such as create X content) is not checked for those targets. Derived ids (<prefix>:<…>) are not checked either. For anything else, list the target in knownServices, knownRoutes, knownPermissions or knownLibraries.
- No Twig. Templates,
hook_theme and anything defined in PHP are out of scope in 0.1.
- No PHP inheritance. A method defined in a parent class or a trait is not resolved, so
methodMissing stays silent on classes that extends or use a trait.
- Not covered in 0.1:
*.layouts.yml, *.breakpoints.yml, config schemas, migrations, recipes, autowiring by attributes.
- It never edits your files and never runs PHP, Drush or any project code.
Getting started
- Install timaub's YAML Lint for Drupal from the Extensions view.
- Open a Drupal project, a
web/ docroot, or a single module or theme. The extension activates when the workspace contains a *.routing.yml, *.services.yml, *.permissions.yml, *.libraries.yml or *.links.*.yml file.
- Open the Problems panel (
Ctrl+Shift+M / Cmd+Shift+M). Findings appear there and as squiggles; they update when you open, edit (after a short pause) or save a Drupal YAML file; an unsaved file is checked with its in-editor content.
- Run timaub's YAML Lint for Drupal: Scan Workspace to rescan everything. The timaub's YAML Lint for Drupal view in the Explorer groups findings by folder and file; click one to jump to it.
The whole workspace is indexed, including core/ and contrib/ if present, so their routes, services and libraries count as existing. Only your own code gets diagnostics: core/, contrib/, vendor/ and node_modules/ are excluded by lintExclude (a file you open is always checked).
The status bar shows Drupal YAML: N issues (plus · Free without a license); click it to rescan.
Pro
Pro unlocks the permissionMissing, libraryMissing, assetMissing, moduleMissing and linkParentMissing rules, and timaub's YAML Lint for Drupal: Export Report as CSV (Pro) (columns file,line,rule,severity,target,message, ready for a ticket or a code review).
Without a license, Pro rules are skipped silently: no squiggles, no reminder on every save.
Buy: https://buy.polar.sh/polar_cl_dKveV2oJiaRLj5Cau4uGdEDp7iDiXgiilWe9z17CgEC — €39/year.
Activate: run timaub's YAML Lint for Drupal: Enter License Key and paste the key from your purchase e-mail.
- One license = one named user, on up to 3 machines. Run timaub's YAML Lint for Drupal: Deactivate License to free a machine; an activation you can no longer reach can be released from the Polar customer portal (link in your purchase e-mail).
- The key is checked online when you enter it, then revalidated silently at most once every 24 hours. If you are offline, Pro keeps working for 14 days after the last successful check.
- timaub's YAML Lint for Drupal: Show License Status shows the current state.
Settings
| Setting |
Type |
Default |
Description |
drupalYamlLint.exclude |
string[] |
["**/node_modules/**", "**/vendor/**", "**/.git/**"] |
Globs excluded from the index entirely. |
drupalYamlLint.lintExclude |
string[] |
["**/core/**", "**/contrib/**", "**/vendor/**", "**/node_modules/**"] |
Indexed (their targets count as existing) but no diagnostics. Open files are always checked. |
drupalYamlLint.knownServices |
string[] |
[] |
Service ids to treat as declared (ServiceProvider, compiler pass). |
drupalYamlLint.knownRoutes |
string[] |
[] |
Route names to treat as existing (dynamic routes). |
drupalYamlLint.knownPermissions |
string[] |
[] |
Permissions to treat as declared (permission callbacks). |
drupalYamlLint.knownLibraries |
string[] |
[] |
Libraries (module/name) to treat as declared (hook_library_info_build). |
drupalYamlLint.rules.<rule> |
error | warning | information | hint | off |
see table above |
Severity of each of the 10 rules, e.g. drupalYamlLint.rules.methodMissing. |
drupalYamlLint.scanOnOpen |
boolean |
true |
Recompute diagnostics automatically when a Drupal YAML file is opened, edited (after a short pause) or saved. When off, run Scan Workspace manually. |
drupalYamlLint.maxFiles |
number |
5000 |
Maximum number of YAML files indexed per workspace folder in each scan. |
The known* settings are exact strings, never patterns: nothing from the workspace is executed, so the extension runs fully in Restricted Mode.
Commands
All commands are in the Command Palette under the timaub's YAML Lint for Drupal category. No default keybindings.
| Command |
What it does |
| timaub's YAML Lint for Drupal: Scan Workspace |
Rebuild the index and rescan every Drupal YAML file. |
| timaub's YAML Lint for Drupal: Export Report as CSV (Pro) |
Save the current findings as a CSV file where you choose. |
| timaub's YAML Lint for Drupal: Enter License Key |
Activate Pro. |
| timaub's YAML Lint for Drupal: Deactivate License |
Release this machine's activation and forget the key. |
| timaub's YAML Lint for Drupal: Show License Status |
Show whether Pro is active, running on the offline grace period, or invalid. |
Privacy
timaub's YAML Lint for Drupal collects no data; its only network request is the Pro license check with Polar. Details: PRIVACY.md.
FAQ
Does it work offline?
Yes. Indexing and analysis run locally, with no PHP, Drush, Composer or database. Only the Pro license check goes online, when you enter a key and then at most once a day; Pro keeps working 14 days without a connection.
Does it collect anything about my code?
No. No telemetry, no analytics, no identifier. Your YAML and PHP files never leave your machine. Without a license key the extension makes no network request at all.
It reports a service, route or permission that does exist.
It is probably built in PHP (ServiceProvider, route subscriber, permission callback, hook_library_info_build) in a way the extension does not detect. Add the exact name to knownServices, knownRoutes, knownPermissions or knownLibraries, or set the rule to off. Please also report it: silence on dynamic targets is a design goal.
Why no warning about @entity_type.manager when I open a single module?
Because core is not in the workspace, so the extension cannot know what exists there. Open the Drupal root (or add it as a second folder of a multi-root workspace) to get core-level checks.
Does it work with multi-root workspaces?
Yes, in the free edition too. Each folder is indexed separately and the status bar shows the total.
Open VSX / VSCodium?
The extension uses no Marketplace-only API and runs as-is in VSCodium and other VS Code–compatible editors. Open VSX listing: https://open-vsx.org/extension/timaub/yaml-lint-for-drupal.
Can I get a refund?
Full refund within 14 days of purchase, no questions asked — write to support@timaub.fr.
Is this an official Drupal project?
No. It is an independent tool for Drupal developers, not affiliated with or endorsed by the Drupal Association. Drupal is a registered trademark of Dries Buytaert.
Known limitations
- PHP is read as text: a class is "found" when
src/…/Name.php exists and declares it; methods are matched by function name(. No inheritance, no traits, no attributes.
- Only
Drupal\<module>\…, Drupal\Core\… and Drupal\Component\… classes are resolved (PSR-4); other namespaces are never checked.
- Large repositories: only the first
maxFiles YAML files (default 5000) per folder are indexed; when that cap is reached, the rules that depend on a complete index (routes, services, permissions, libraries, link parents, module dependencies) are suspended for that folder and a warning says so; files over 2 MB are skipped.
Français
timaub's YAML Lint for Drupal vérifie que vos YAML Drupal pointent vers du code qui existe, pendant que vous tapez, hors ligne, sans PHP ni Drupal installé. Les fautes de frappe dans un namespace, un @service, un route_name ou un chemin css/js apparaissent dans le panneau Problèmes au lieu d'un écran blanc après drush cr.
Règles. Gratuit : YAML illisible (parseError), classe PHP introuvable (classMissing), méthode introuvable (methodMissing), service non déclaré (serviceMissing), route inconnue (routeMissing), vue rapport, scan du workspace, multi-root. Pro : permission non déclarée, librairie inconnue, fichier css/js absent, module dépendant absent, lien parent inconnu, export CSV.
Silence plutôt que faux positifs. Un contrôle se tait quand sa cible n'est pas indexable : module absent du workspace, core absent, routes, services ou permissions dynamiques. Pas de Twig ni d'héritage PHP en 0.1. Pour une cible construite en PHP, ajoutez-la à knownServices, knownRoutes, knownPermissions ou knownLibraries.
Pro. Achat : https://buy.polar.sh/polar_cl_dKveV2oJiaRLj5Cau4uGdEDp7iDiXgiilWe9z17CgEC (39 € par an). Lancez timaub's YAML Lint for Drupal: Enter License Key et collez la clé reçue par e-mail. Une licence = un utilisateur, jusqu'à 3 machines ; hors ligne, Pro reste actif 14 jours après la dernière vérification réussie.
Confidentialité. L'extension ne collecte aucune donnée et n'écrit jamais dans vos fichiers (sauf le CSV que vous exportez). Le seul appel réseau est la vérification de la clé Pro auprès de Polar. Détails : PRIVACY.md.
Outil indépendant, sans lien avec la Drupal Association. Drupal est une marque déposée de Dries Buytaert.
License (EULA) · Changelog · Support: support@timaub.fr