clockworklabs/SpacetimeDB · error · syn::Error

views must be `public`, e.g. `#[view(public)]`

Error message

views must be `public`, e.g. `#[view(public)]`

What it means

Compile-time error from the #[spacetimedb::view] macro, raised right after the accessor check: every SpacetimeDB view must currently be public, so when the attribute list lacks the public flag the macro refuses to expand rather than defaulting to private. It is reported at the attribute's call site.

Solutions

  1. Add the public flag: #[spacetimedb::view(public, accessor = person)].
  2. If you wanted a non-public view, note the macro currently requires public on all views - keep it as a plain query helper instead.

Example fix

// before
#[spacetimedb::view(accessor = person)]

// after
#[spacetimedb::view(public, accessor = person)]
Defensive patterns

Strategy: validation

Prevention

When it happens

Trigger: Declaring a view whose attribute list has accessor = ... but not the word public, e.g. #[spacetimedb::view(accessor = person)].

Common situations: Authors expecting a private default for views; converting a query helper into a view and carrying over only the accessor argument; writing pub or pub(crate) instead of public inside the attribute (unknown words are ignored).

Related errors


AI-assisted analysis of clockworklabs/SpacetimeDB@6dee26c6ef (2026-08-20). Data as JSON: /api/errors/b87f9fac00643889. Report an issue: GitHub.

Appendix: source

Thrown at crates/bindings-macro/src/view.rs:89

                    accessor = Some(meta.value()?.parse()?);
                }
                sym::primary_key => {
                    check_duplicate_msg(&primary_key, &meta, "`primary_key` already specified")?;
                    primary_key = Some(ViewPrimaryKeyArg::parse(meta.value()?)?);
                }
            });
            Ok(())
        })
        .parse2(input)?;
        let accessor = accessor.ok_or_else(|| {
            let view = func_ident.to_string().to_snake_case();
            syn::Error::new(
                Span::call_site(),
                format_args!("must specify view accessor, e.g. `#[spacetimedb::view(accessor = {view})]"),
            )
        })?;
        let () = public
            .ok_or_else(|| syn::Error::new(Span::call_site(), "views must be `public`, e.g. `#[view(public)]`"))?;
        Ok(Self {
            name,
            primary_key,
            public: true,
            accessor,
        })
    }
}

/// If `ty` is `impl Query<T>`, returns `Some(T)`. Otherwise `None`.
fn extract_impl_query_inner(ty: &syn::Type) -> Option<&syn::Type> {
    if let syn::Type::ImplTrait(impl_trait) = ty {
        for bound in &impl_trait.bounds {
            if let syn::TypeParamBound::Trait(trait_bound) = bound
                && let Some(seg) = trait_bound.path.segments.last()
                && seg.ident == "Query"
                && let syn::PathArguments::AngleBracketed(args) = &seg.arguments
                && let Some(syn::GenericArgument::Type(inner)) = args.args.first()

View on GitHub (pinned to 6dee26c6ef)