clockworklabs/SpacetimeDB · error

ERROR: Table '%s' not found for default value on field '%s'

Error message

ERROR: Table '%s' not found for default value on field '%s'

What it means

V9Builder::AddColumnDefault resolves the table by name before attaching a serialized default value; when findTableByName finds no match, it prints this and returns, so the column default is silently dropped and the module publishes without it. Inserts that relied on the default will then require an explicit value (or fail), which is often how this is first noticed.

Source

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

    index_def.accessor_name = index_name;  // User-provided index name for access
    index_def.algorithm = algorithm;
    
    // Add to table's indexes
    table->indexes.push_back(std::move(index_def));
    
    //fprintf(stdout, "DEBUG: Successfully added multi-column index '%s' -> '%s' with %zu fields\n",
    //        index_name.c_str(), generated_name.c_str(), field_indexes.size());
}

// Template implementation for AddColumnDefault
template<typename T>
void V9Builder::AddColumnDefault(const std::string& table_name,
                                 const std::string& field_name,
                                 const std::vector<uint8_t>& serialized_value) {
    // Find the existing table
    RawTableDefV9* table = findTableByName(table_name);
    if (!table) {
        fprintf(stderr, "ERROR: Table '%s' not found for default value on 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. Match the table name string in the default annotation exactly to the table macro's name
  2. Compile the table and its default annotation in the same translation unit to fix static-init ordering
  3. Check for duplicate table name registrations that overwrote the original
  4. After republishing, verify the column default shows in the table description

Example fix

// before
ST_TABLE(player, ...);
ST_COLUMN_DEFAULT(players, score, 0);   // wrong table name
// after
ST_COLUMN_DEFAULT(player, score, 0);
Defensive patterns

Strategy: validation

Validate before calling

#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 default-value annotation's table_name string doesn't exactly match a registered table (typo/casing/renamed table), or the default registration static object initializes before the table's registration in another translation unit.

Common situations: Table renames during schema evolution; default annotations kept in a central file that initializes before the tables; copy-paste between similar table names; mixing macro generations so the table is registered under a different builder.

Related errors


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