clockworklabs/SpacetimeDB · error

ERROR: Table '%s' not found when trying to add constraint to

Error message

ERROR: Table '%s' not found when trying to add constraint to field '%s'

What it means

V9Builder::AddFieldConstraint looks up the raw table definition by name via findTableByName (exact, case-sensitive match against RawTableDefV9::name) before attaching a primary-key/unique/auto-inc constraint. When no registered table matches, it prints this error and returns, silently dropping the constraint — the module still builds, but the column ends up without the intended constraint.

Source

Thrown at crates/bindings-cpp/include/spacetimedb/internal/v9_builder.h:437

        pending_schedules_.erase(schedule_it);
    }
    
    // Add the complete V9 table definition
    AddV9Table(table_name, table_type, &typeid(T), is_public,
               primary_key, indexes, v9_constraints, sequences, schedule);
}

// Template implementation for AddFieldConstraint
template<typename T>
void V9Builder::AddFieldConstraint(const std::string& table_name,
                                   const std::string& field_name,
                                   FieldConstraint constraint) {
    // AddFieldConstraint implementation
    
    // Find the existing table by name
    RawTableDefV9* table = findTableByName(table_name);
    if (!table) {
        fprintf(stderr, "ERROR: Table '%s' not found when trying to add constraint to field '%s'\n",
                table_name.c_str(), field_name.c_str());
        return;
    }
    
    // Get field descriptors to find the field index
    SpacetimeDB::field_registrar<T>::register_fields();
    auto& descriptor_map = SpacetimeDB::get_table_descriptors();
    auto it = descriptor_map.find(&typeid(T));
    if (it == descriptor_map.end()) {
        fprintf(stderr, "ERROR: No field descriptors found for table %s\n", table_name.c_str());
        return;
    }
    
    const auto& field_descs = it->second.fields;
    uint16_t field_idx = 0;
    bool field_found = false;
    
    // Find the field index

View on GitHub (pinned to 524b4487d9)

Solutions

  1. Compare the table name in the constraint registration against the exact string used in the table macro (case-sensitive)
  2. Ensure the table's static registration object is compiled/linked such that it runs before the constraint — prefer keeping table and constraint in the same translation unit
  3. Check for duplicate table registrations where the second one renamed/replaced the first
  4. After fixing, republish and describe the table to confirm the constraint exists

Example fix

// before — names disagree: constraint targets 'Users', table registered as 'users'
ST_TABLE(users, ...);
ST_UNIQUE(Users, id);   // typo -> constraint silently dropped
// after
ST_TABLE(users, ...);
ST_UNIQUE(users, id);
Defensive patterns

Strategy: validation

Validate before calling

// Before relying on constraints, verify the table name resolved (after init):
#include <spacetimedb/internal/v9_builder.h>
bool TableIsRegistered(const std::string& name) {
    for (const auto& t : SpacetimeDB::Internal::GetV9Module().tables)
        if (t.name == name) return true;
    return false;
}

Prevention

When it happens

Trigger: The constraint macro is instantiated with a table_name string that differs from the registered table name (typo, casing, renamed table), or the constraint registration runs before the table's own static registration in another translation unit, or the table macro and constraint macro disagree on the generated name.

Common situations: Renaming a table (or its ST_TABLE name argument) without updating the constraint annotation; copy-pasting constraint macros between tables and forgetting to change the name; static-init ordering differences between .cpp files causing the constraint to run first; name collision resolved by overwriting the earlier table.

Related errors


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