denoland/deno · error · syn::Error
FromV8 enum derive currently supports only unit and single-e
Error message
FromV8 enum derive currently supports only unit and single-element newtype variants
What it means
#[derive(FromV8)] on an enum currently implements only the externally-tagged shape: unit variants (matched by their camelCased tag string) and single-element newtype variants (matched when the key exists and is not undefined). Any struct variant (V { a: u32 }) or tuple variant with zero or 2+ fields falls into the catch-all arm and produces this compile-time error on the offending variant's span.
Source
Thrown at libs/ops/conversion/from_v8/enum.rs:82
}
};
let key = crate::get_internalized_string(Ident::new(
&tag_name,
variant_ident.span(),
))?;
variant_arms.push(quote! {
{
let __key = #key;
if let Some(__inner) = __obj.get(__scope, __key)
&& !__inner.is_undefined()
{
return Ok(Self::#variant_ident(#converter));
}
}
});
}
_ => {
return Err(Error::new(
variant_span,
"FromV8 enum derive currently supports only unit and single-element newtype variants",
));
}
}
}
let unit_branch = if unit_arms.is_empty() {
quote! {}
} else {
quote! {
if let Ok(__s) =
::deno_core::v8::Local::<::deno_core::v8::String>::try_from(__value)
{
let __s = __s.to_rust_string_lossy(__scope);
match __s.as_str() {
#(#unit_arms)*
_ => {View on GitHub (pinned to 9ad36f7a2c)
Solutions
- Convert each struct/multi-field variant into a newtype variant wrapping a struct: move the fields into their own #[derive(FromV8)] struct and declare the variant as Point(Point).
- Keep single payloads as one-field newtype variants (V(u32)) — those and unit variants are the only supported shapes.
- For complex payloads, use the serde path on the newtype variant so serde_v8::from_v8 handles the inner value instead of the derive.
Example fix
// before
#[derive(FromV8)]
enum Shape {
Circle,
Point { x: f64, y: f64 }, // error: only unit and single-element newtype variants
}
// after
#[derive(FromV8)]
struct Point {
x: f64,
y: f64,
}
#[derive(FromV8)]
enum Shape {
Circle,
Point(Point), // newtype variant wrapping a derived struct
} Defensive patterns
Strategy: validation
Type guard
// design-time shape check: FromV8-compatible enum variants are unit or single-newtype only
// variant is OK: Unit | Newtype(OneType)
// variant is NOT: Struct { a: A } | Tuple(A, B) | Empty()
// when reviewing an enum before adding #[derive(FromV8)]:
// every variant must match `Ident` or `Ident(Ty)` with exactly one Ty Prevention
- Keep op-facing FromV8 enums to unit + single-newtype variants; model richer payloads as separate derived structs wrapped in newtype variants.
- Mirror the supported shapes in a test file that derives FromV8, so CI catches unsupported variants the moment they are added.
- Remember ToV8 is more permissive than FromV8 — never assume an enum that serializes can also be deserialized by these derives.
When it happens
Trigger: Deriving FromV8 on an enum that contains a struct variant like Point { x: f64, y: f64 } or a multi-field tuple variant like Pair(u32, u32); also a variant declared with empty parens V().
Common situations: Porting serde-tagged enums into deno_core ops and expecting the same flexibility; adding a data-carrying variant to a previously unit-only op enum; mixing #[to_v8] (which does support struct variants) with #[from_v8] and assuming symmetric support.
Related errors
- Unions are not supported
- Unit fields are currently not supported
- Cannot use serde on unit variant
- Cannot combine `untagged` with `tag` or `content`
- `content` requires `tag` to be specified
AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20).
Data as JSON: /api/errors/d065df6ed2c80a44.
Report an issue: GitHub.