oxc-project/oxc · error · OxcDiagnostic
Unexpected {} in "{}" computed property.
Error message
Unexpected {} in "{}" computed property. What it means
Diagnostic from oxlint's vue/no-async-in-computed-properties rule (since oxlint 1.71.0). It fires when a computed property (object entry under `computed`) contains asynchronous work: an async function declaration, an await operator, a Promise object, a .then/.catch/.finally chain, or a timed function like setTimeout. Vue computed properties must be synchronous; async ones return a Promise that never updates reactively, producing values that render as empty or stale forever.
Source
Thrown at crates/oxc_linter/src/rules/vue/no_async_in_computed_properties.rs:42
NewPromise,
Asynchronous,
Timed,
}
impl AsyncKind {
fn as_str(self) -> &'static str {
match self {
Self::AsyncFunction => "async function declaration",
Self::Await => "await operator",
Self::NewPromise => "Promise object",
Self::Asynchronous => "asynchronous action",
Self::Timed => "timed function",
}
}
}
fn unexpected_in_property(span: Span, kind: AsyncKind, key: &str) -> OxcDiagnostic {
OxcDiagnostic::warn(format!("Unexpected {} in \"{}\" computed property.", kind.as_str(), key))
.with_label(span)
}
fn unexpected_in_function(span: Span, kind: AsyncKind) -> OxcDiagnostic {
OxcDiagnostic::warn(format!("Unexpected {} in computed function.", kind.as_str()))
.with_label(span)
}
#[derive(Debug, Default, Clone, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "camelCase", default, deny_unknown_fields)]
struct NoAsyncInComputedPropertiesConfig {
/// Names of identifiers whose member-call chains (`.then` / `.catch` / `.finally`)
/// should be ignored. Useful for libraries like Zod where `.catch(default)` is
/// a builder API, not a Promise method.
ignored_object_names: FxHashSet<String>,
}
#[derive(Debug, Default, Clone, Deserialize, Serialize, JsonSchema)]View on GitHub (pinned to e1e7af627c)
Solutions
- Move the async work into a method, watch/watchEffect, or onMounted and store the result in a ref/data property
- Keep the computed synchronous and derive from already-loaded state
- If the flagged member chain is a builder API (e.g., zod's .catch), add the object name to ignoredObjectNames: { "ignoredObjectNames": ["z"] }
Example fix
// before
computed: {
async user() { return await fetchUser(this.id) },
}
// after
data: () => ({ user: null }),
watch: {
id: {
immediate: true,
async handler(id) { this.user = await fetchUser(id) },
},
} Defensive patterns
Strategy: validation
Validate before calling
# scan computed blocks for async constructs
grep -rnA20 "computed: *{" --include='*.vue' src | grep -nE "async |await |\.then\(|new Promise|setTimeout" Prevention
- Keep computed properties pure and synchronous by convention; do async work in watch/watchEffect/lifecycle hooks
- Configure ignoredObjectNames for fluent builder APIs (zod .catch) to avoid false positives
- Enable this rule before code review so async computed never lands
When it happens
Trigger: `computed: { foo: async function() {...} }`, a computed whose body contains `await`, `new Promise(...)`, `someCall().then(...)`, or setTimeout/setInterval, where the object is a Vue component options object.
Common situations: Loading data inside computed because it 'derives' from props; chaining a Promise-returning API in a getter; accidentally flagging builder APIs like Zod's .catch() — the rule's ignoredObjectNames config (ignored_object_names) exists exactly to whitelist those.
Related errors
- Unexpected {} in computed function.
- Change to `throw new TypeError(...)`
- encountered allocation error
- Avoid destructuring from `defineProps`.
- The computed property cannot be used in `data()` because it
AI-assisted analysis of oxc-project/oxc@e1e7af627c (2026-08-20).
Data as JSON: /api/errors/2a47b75cab84b380.
Report an issue: GitHub.