Skip to content

OD601 unresolved-js-import

A JS import names a module or an export no indexed module provides.

Category Severity Series Needs the index
Correctness Error all yes

What it reports

An import or export ... from in a script under static/src whose module path an indexed module should provide but does not, whose named export that file lacks, or whose module is missing from depends. A module that Odoo always installs with base, such as web, counts as in depends. A path @sale/js/x names sale/static/src/js/x.js, and a relative path is read from the importing file. An export counts when the file declares it, re-exports it, or may get it through an export * the index cannot follow.

A patch on a class that is gone, such as patch(Missing.prototype, {...}), is reported here, at the import of Missing.

Why it matters

Odoo starts a bundle's modules in dependency order. A module whose path no file provides is never started, nor is any module that imports it, and the web client reports the missing dependencies. A name the module does not export is imported as undefined, so the first use fails: at load for a patch or an extends, later for a function call or a component's template. A module missing from depends may not be installed, and then its files are in no bundle. The usual cause is a file moved or a name renamed in web or another module between series.

The rule checks only scripts a bundle of some indexed manifest adds, and only those Odoo loads as ES modules: every script under static/src from 17.0 on, and before that only those annotated @odoo-module. A script marked @odoo-module ignore is skipped. Paths of a module that is not indexed, or whose scripts are not, such as @odoo/owl, are not checked.

A module missing from depends is not reported when a dependency that is not indexed, such as an Enterprise module, could load it. Add the checkout of that dependency to --addons-path to check the imports. A missing file or export is reported all the same, since a path names a file of the module it starts with, which no other module can add to, so a module the scan holds whole is still checked.

Example

static/src/js/partner_list.js
import { useService } from "@web/core/utils/hook";

web has core/utils/hooks.js, so no file provides @web/core/utils/hook.

static/src/js/partner_list.js
import { useService } from "@web/core/utils/hooks";

Suppressing

// odooscan: ignore[OD601]
import { useService } from "@web/core/utils/hook";

See suppressing a finding.