oxc-project/oxc · warning · OxcDiagnostic
Avoid using non-standard `Promise.{prop_name}` method.
Error message
Avoid using non-standard `Promise.{prop_name}` method. What it means
Diagnostic from the oxlint rule `promise/spec-only` (plugin `promise`, category `restriction`). It fires on member expressions whose object is exactly the identifier `Promise` and whose static property name is NOT in the built-in PROMISE_STATIC_METHODS allowlist (the standard set: resolve, reject, all, allSettled, any, race, try, withResolvers, ...) and not whitelisted via the `allowedMethods` config option (case-sensitive set). Note it fires on property access alone - `getA(Promise.done)` is flagged even without a call. Non-standard statics tie code to specific libraries (e.g. Bluebird) or polyfills and cost maintenance.
Source
Thrown at crates/oxc_linter/src/rules/promise/spec_only.rs:17
use oxc_diagnostics::OxcDiagnostic;
use oxc_macros::declare_oxc_lint;
use oxc_span::{GetSpan, Span};
use oxc_str::CompactStr;
use rustc_hash::FxHashSet;
use schemars::JsonSchema;
use serde::Deserialize;
use crate::{
AstNode,
context::LintContext,
rule::{DefaultRuleConfig, Rule},
utils::PROMISE_STATIC_METHODS,
};
fn spec_only(prop_name: &str, member_span: Span) -> OxcDiagnostic {
OxcDiagnostic::warn(format!("Avoid using non-standard `Promise.{prop_name}` method."))
.with_label(member_span)
}
#[derive(Debug, Default, Clone, Deserialize)]
pub struct SpecOnly(Box<SpecOnlyConfig>);
#[derive(Debug, Default, Clone, Deserialize, JsonSchema)]
#[serde(rename_all = "camelCase", default, deny_unknown_fields)]
pub struct SpecOnlyConfig {
/// List of Promise static methods that are allowed to be used.
allowed_methods: Option<FxHashSet<CompactStr>>,
}
impl std::ops::Deref for SpecOnly {
type Target = SpecOnlyConfig;
fn deref(&self) -> &Self::Target {
&self.0View on GitHub (pinned to e1e7af627c)
Solutions
- Replace with a standard equivalent: `Promise.done(p)` becomes `p.catch(err => console.error(err))`
- Whitelist intentional extensions: `{ "allowedMethods": ["map", "done"] }` (exact case)
- Import the extension library under its own namespace (`Promise = require('bluebird')` locally) instead of relying on the patched global
Example fix
// before Promise.done(fetchThing()) // after fetchThing().catch(err => console.error(err))
Defensive patterns
Strategy: validation
Validate before calling
npx oxlint --promise/spec-only src/
# intentional extensions:
# { "rules": { "promise/spec-only": ["error", { "allowedMethods": ["map", "done"] }] } } Type guard
// Constrain static access to the spec surface at the type level: type PromiseStatic = | 'resolve' | 'reject' | 'all' | 'allSettled' | 'any' | 'race' | 'try' | 'withResolvers'; const isSpecStatic = (name: string): name is PromiseStatic => ['resolve', 'reject', 'all', 'allSettled', 'any', 'race', 'try', 'withResolvers'].includes(name);
Prevention
- Use standard statics; reach for `Promise.all`/`Promise.allSettled` instead of library combinators
- Import extension libraries under their own namespace rather than patched globals
- Keep the `allowedMethods` whitelist in shared config, exact case (matching is case-sensitive)
When it happens
Trigger: `Promise.done()`; `Promise.map(items, fn)` (Bluebird); `Promise.promisify(fn)`; any `Promise.<unknown>()` access; a method listed in `allowedMethods` with different casing (matching is case-sensitive per the tests).
Common situations: Bluebird-era codebases; legacy `Promise.done` used as terminal catch; polyfills adding statics to the global; enabling the `restriction` category during an oxlint adoption.
Related errors
- Promise executor functions should not be `async`.
- Unexpected `await` inside a loop.
- Avoid nesting promises.
- Do not use `new` on `Promise.{static_name}`
- Avoid using promises inside of callbacks.
AI-assisted analysis of oxc-project/oxc@e1e7af627c (2026-08-20).
Data as JSON: /api/errors/fc91da9535b8ff4f.
Report an issue: GitHub.