oxc-project/oxc · error · OxcDiagnostic

Props are defined in both `defineProps` and `export default

Error message

Props are defined in both `defineProps` and `export default {}`.

What it means

Diagnostic from the oxlint rule `vue/valid-define-props`. Before scanning calls, the rule computes `has_other_script_emits = has_default_exports_property(&ctx.other_file_hosts(), "props")` — true when a sibling plain `<script>` block exports a default object containing a `props` property. If `defineProps` also declares props in `<script setup>`, the helper returns `DefineMacroProblem::DefineInBoth`. Declaring props twice makes the two declarations compete and the compiled component's props become ambiguous.

Source

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

            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.
    ///
    /// This rule reports `defineProps` compiler macros in the following cases:
    ///
    /// - `defineProps` is referencing locally declared variables.
    /// - `defineProps` has both a literal type and an argument. e.g. `defineProps<{ /*props*/ }>({ /*props*/ })`
    /// - `defineProps` has been called multiple times.
    /// - Props are defined in both `defineProps` and `export default {}`.

View on GitHub (pinned to e1e7af627c)

Solutions

  1. Remove the `export default {}` from the plain `<script>` block (help text: 'Remove `export default`') and keep props solely in `defineProps`.
  2. Alternatively keep `export default { props: {...} }` and delete the `defineProps` call — but never both.
  3. After removing, re-run lint: the companion 'Props are not defined' diagnostic also disappears only if one declaration remains.

Example fix

// before
<script>
export default { props: { msg: String } }
</script>
<script setup>
defineProps({ count: Number })
</script>

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

Strategy: validation

Validate before calling

const bothWays =
  /export\s+default\s*\{[\s\S]*?\bprops\s*:/.test(src) &&
  /\bdefineProps\s*[(<]/.test(setup);
if (bothWays) {
  throw new Error('Props declared both in export default {} and defineProps — remove one');
}

Prevention

When it happens

Trigger: A .vue file (VueSetup) that has BOTH `<script> export default { props: { msg: String } } </script>` AND a `defineProps({ count: Number })` in `<script setup>`. Any `defineProps` call with a declaration (argument or type parameter) while the sibling `export default {}` has a `props` key triggers it; the diagnostic span is the `defineProps` call.

Common situations: Partial migration from Options API where `export default { props }` was left behind after adding `defineProps`; mixing both styles in one file because examples were combined; tooling that injects `defineProps` into files that still declare props the old way.

Related errors


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