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

Every `#[spacetimedb::view]` must explicitly opt in with `public` (currently the only visibility), keeping the access decision explicit. The check runs after the accessor check, so if both are missing you will see the accessor error first. Emitted at call site when `public` was not among the arguments.

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 524b4487d9)

Solutions

  1. Add `public` to the attribute: `#[spacetimedb::view(accessor = v, public)]`
  2. If an accessor error also appears, fix it first — it is checked before this one

Example fix

// before
#[spacetimedb::view(accessor = top_scores)]
fn top_scores() -> impl Query<Score> { ... }

// after
#[spacetimedb::view(accessor = top_scores, public)]
fn top_scores() -> impl Query<Score> { ... }
Defensive patterns

Strategy: validation

Validate before calling

# list view attributes lacking public
grep -rn 'spacetimedb::view' src/ | grep -v public || echo OK

Prevention

When it happens

Trigger: `#[spacetimedb::view(accessor = v)]` with `accessor` present but `public` absent.

Common situations: Copying a view declaration and dropping the `public` argument; assuming views are public by default.

Related errors


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