clockworklabs/SpacetimeDB · error · Exception

InvalidTableVisibility

InvalidTableVisibility

Error message

Table row type visibility must be public or internal, including containing types.

What it means

Compile-time error from the SpacetimeDB C# module source generator. When scanning a [Table] row type, Module.cs walks the type and all its containing types and only accepts Accessibility.Public, Internal, ProtectedAndInternal or NotApplicable; any private/protected/protected-or-internal nesting level makes the generator report InvalidTableVisibility and throw, aborting code generation. The row type must be at least as visible as every containing type.

Source

Thrown at crates/bindings-csharp/Codegen/Module.cs:536

        var container = context.TargetSymbol;
        Visibility = container.DeclaredAccessibility;
        while (container != null)
        {
            switch (container.DeclaredAccessibility)
            {
                case Accessibility.ProtectedAndInternal:
                case Accessibility.NotApplicable:
                case Accessibility.Internal:
                case Accessibility.Public:
                    if (Visibility < container.DeclaredAccessibility)
                    {
                        Visibility = container.DeclaredAccessibility;
                    }
                    break;
                default:
                    diag.Report(ErrorDescriptor.InvalidTableVisibility, typeSyntax);
                    throw new Exception(
                        "Table row type visibility must be public or internal, including containing types."
                    );
            }

            container = container.ContainingType;
        }

        TableAccessors = new(
            context.Attributes.Select(a => new TableAccessor(this, a, diag)).ToImmutableArray()
        );
        Indexes = new(
            context
                .TargetSymbol.GetAttributes()
                .Where(TableIndex.CanParse)
                .Select(a => new TableIndex(this, a, diag))
                .ToImmutableArray()
        );
    }

View on GitHub (pinned to 3653d2ed49)

Solutions

  1. Make the [Table] row type `public` (simplest and always accepted)
  2. If it is nested, make every containing class `public` or `internal` as well
  3. Rebuild after the change so the source generator re-runs and emits the table boilerplate

Example fix

// before
public static class Module {
    [Table]
    private class Player { public uint Id; } // InvalidTableVisibility
}

// after
public static class Module {
    [Table]
    public class Player { public uint Id; }
}
Defensive patterns

Strategy: validation

Validate before calling

// Check before adding [Table]: row type and all containers must be public/internal
static bool IsTableVisible(Type t)
{
    for (var c = t; c is not null; c = c.DeclaringType)
        if (c.IsNestedPrivate || c.IsNestedFamily || c.IsNestedFamORAssem)
            return false; // private / protected / protected-or-internal are rejected
    return true;
}

Prevention

When it happens

Trigger: Putting [Table]/[Table(name, public=true)] on a private nested class, a protected nested class, or a public class nested inside a private class; declaring the row type with `internal` inside a `private` outer type also fails because Visibility must be raised to the container's accessibility.

Common situations: New module projects keeping tables nested inside a Program/Module helper class marked private; refactoring that moves tables into internal helper classes; copying sample code where the enclosing class lost its public modifier; Unity-style file-scoped nesting habits applied to SpacetimeDB modules.

Related errors


AI-assisted analysis of clockworklabs/SpacetimeDB@3653d2ed49 (2026-08-20). Data as JSON: /api/errors/4be800cdbc10c8da. Report an issue: GitHub.