oxc-project/oxc · error · OxcDiagnostic

The `{deprecated}` lifecycle hook is deprecated. Use `{repla

Error message

The `{deprecated}` lifecycle hook is deprecated. Use `{replacement}` instead.

What it means

Diagnostic from oxlint's vue/no-deprecated-destroyed-lifecycle rule (since oxlint 1.35.0). It fires when a component uses the Vue 2 lifecycle hooks `destroyed` or `beforeDestroy`: in Vue 3 they were renamed to `unmounted` and `beforeUnmount`, and the old names are silently never invoked, so cleanup code simply stops running (leaks, lingering listeners). The message and help text interpolate the deprecated hook and its replacement.

Source

Thrown at crates/oxc_linter/src/rules/vue/no_deprecated_destroyed_lifecycle.rs:20

    AstKind,
    ast::{
        CallExpression, ExportDefaultDeclarationKind, Expression, ObjectExpression,
        ObjectPropertyKind, PropertyKey,
    },
};
use oxc_diagnostics::OxcDiagnostic;
use oxc_macros::declare_oxc_lint;
use oxc_span::Span;
use rustc_hash::FxHashSet;

use crate::{context::LintContext, rule::Rule};

fn no_deprecated_destroyed_lifecycle_diagnostic(
    span: Span,
    deprecated: &str,
    replacement: &str,
) -> OxcDiagnostic {
    OxcDiagnostic::warn(format!(
        "The `{deprecated}` lifecycle hook is deprecated. Use `{replacement}` instead."
    ))
    .with_help(format!("Replace `{deprecated}` with `{replacement}`."))
    .with_label(span)
}

#[derive(Debug, Default, Clone)]
pub struct NoDeprecatedDestroyedLifecycle;

declare_oxc_lint!(
    /// ### What it does
    ///
    /// Disallow using deprecated `destroyed` and `beforeDestroy` lifecycle hooks in Vue.js 3.0.0+.
    ///
    /// ### Why is this bad?
    ///
    /// In Vue.js 3.0.0+, the `destroyed` and `beforeDestroy` lifecycle hooks have been renamed
    /// to `unmounted` and `beforeUnmount` respectively. Using the old names is deprecated and

View on GitHub (pinned to e1e7af627c)

Solutions

  1. Rename beforeDestroy to beforeUnmount
  2. Rename destroyed to unmounted
  3. Add this rule to the migration lint set so every renamed hook is caught in one pass

Example fix

// before
beforeDestroy() { this.unsubscribe() },
destroyed() { this.teardown() },
// after
beforeUnmount() { this.unsubscribe() },
unmounted() { this.teardown() },
Defensive patterns

Strategy: validation

Validate before calling

# find Vue 2 destroy lifecycle hooks
grep -rnE "\b(beforeDestroy|destroyed)\s*\(" --include='*.vue' src

Prevention

When it happens

Trigger: A component options object declares a `destroyed` or `beforeDestroy` property (tracked in a FxHashSet of deprecated hook names with their replacements).

Common situations: Components migrated from Vue 2 that keep teardown in destroyed(); nothing crashes, but timers, event listeners, and observers are never cleaned up, producing slow memory leaks that only show up in long sessions.

Related errors


AI-assisted analysis of oxc-project/oxc@e1e7af627c (2026-08-20). Data as JSON: /api/errors/611fa89862904b88. Report an issue: GitHub.