oxc-project/oxc · error · OxcDiagnostic

`defineProps` is referencing locally declared variables.

Error message

`defineProps` is referencing locally declared variables.

What it means

Diagnostic from the oxlint rule `vue/valid-define-props`. When `check_define_macro_call_expression` detects that the argument to `defineProps` references identifiers declared locally in the same `<script setup>` block (as opposed to imports or a sibling `<script>` binding), it returns `DefineMacroProblem::ReferencingLocally`. The Vue compiler cannot statically resolve local variables into the props definition, so the component's props may break silently or be typed incorrectly.

Source

Thrown at crates/oxc_linter/src/rules/vue/valid_define_props.rs:35

}

fn called_multiple_times(span: Span, second_span: Span) -> OxcDiagnostic {
    OxcDiagnostic::warn("`defineProps` has been called multiple times.")
        .with_help("combine all `defineProps` calls into a single `defineProps` call.")
        .with_labels([
            span.label("`defineProps` is called here"),
            second_span.label("`defineProps` is called here too"),
        ])
}

fn events_not_defined(span: Span) -> OxcDiagnostic {
    OxcDiagnostic::warn("Props are not defined.")
        .with_help("Define at least one prop in `defineProps`.")
        .with_label(span)
}

fn referencing_locally(span: Span) -> OxcDiagnostic {
    OxcDiagnostic::warn("`defineProps` is referencing locally declared variables.")
        .with_help("inline the variable or import it from another module.")
        .with_label(span)
}

fn define_in_both(span: Span) -> OxcDiagnostic {
    OxcDiagnostic::warn("Props are defined in both `defineProps` and `export default {}`.")
        .with_help("Remove `export default`.")
        .with_label(span)
}

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

declare_oxc_lint!(
    /// ### What it does
    ///
    /// Enforce valid usage of the `defineProps` compiler macro in Vue.
    ///

View on GitHub (pinned to e1e7af627c)

Solutions

  1. Inline the object: `defineProps({ msg: String })`.
  2. Move the definition into a plain `<script>` block (sibling to `<script setup>`) or another module and import it, as the help text suggests.
  3. Use `// oxlint-disable vue/valid-define-props` on the line only if you have verified the compiler accepts your specific case.

Example fix

// before
<script setup>
const def = { msg: String }
defineProps(def)
</script>

// after
<script setup>
defineProps({ msg: String })
</script>
Defensive patterns

Strategy: validation

Validate before calling

const arg = setup.match(/\bdefineProps\s*\(\s*([a-zA-Z_$][\w$]*)\s*\)\s*;?/);
if (arg && new RegExp(`(?:const|let|var)\\s+${arg[1]}`).test(setup)) {
  throw new Error(`defineProps references local variable '${arg[1]}' — inline it or import it`);
}

Prevention

When it happens

Trigger: `const def = { msg: String }; defineProps(def)` inside `<script setup>` — the argument expression contains an IdentifierReference bound in the same block rather than imported or declared in a sibling `<script>`. The pass tests show allowed shapes: `const def` in plain `<script>` then `defineProps(def)` in `<script setup>`, `import { propsDef } from './defs'; defineProps(propsDef)`, and type-level references like `Array as PropType<typeof strList>` (type positions are not checked).

Common situations: Reusing a shared prop-shape object defined in the same file; grouping prop definitions into a `const` for readability; converting Options API `props: def` directly into `defineProps(def)` without moving `def`.

Related errors


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