clockworklabs/SpacetimeDB · error

ERROR: Field '%s' not found in table '%s'

Error message

ERROR: Field '%s' not found in table '%s'

What it means

AddFieldConstraint resolved the table and its field descriptors, but the requested field_name does not match any field_desc.name in the descriptor list, so it cannot compute the column index and drops the constraint. The comparison is exact and case-sensitive against the names produced by the row type's field registration.

Source

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

        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
    for (const auto& field_desc : field_descs) {
        if (field_desc.name == field_name) {
            field_found = true;
            break;
        }
        field_idx++;
    }
    
    if (!field_found) {
        fprintf(stderr, "ERROR: Field '%s' not found in table '%s'\n", 
                field_name.c_str(), table_name.c_str());
        return;
    }
    
    // Add constraint based on type
    int constraint_bits = static_cast<int>(constraint);
    
    // Check for PrimaryKey (has specific bit 0b1000)
    if (constraint_bits & 0b1000) {  // PrimaryKey-specific bit
        // Validate that there isn't already a primary key
        if (!table->primary_key.empty()) {
            // Set the error flag instead of crashing - this will be handled by preinit_99
            SetMultiplePrimaryKeyError(table_name);
            return; // Exit early to avoid adding the conflicting primary key
        }
        table->primary_key.push_back(field_idx);
        
        // PrimaryKey implies Unique constraint and index

View on GitHub (pinned to 524b4487d9)

Solutions

  1. Verify the field string in the constraint macro exactly matches the C++ member name declared in the row struct (case-sensitive)
  2. If the member was renamed, update every constraint/index/default annotation that references it
  3. Confirm the field is declared in the same struct T that the macro uses, not in a base class or sibling type
  4. Republish and describe the table to confirm the constraint took effect

Example fix

// before
struct User { uint64_t user_id; std::string name; };
ST_UNIQUE(user, id);   // 'id' not among descriptors ('user_id','name')
// after
struct User { uint64_t user_id; std::string name; };
ST_UNIQUE(user, user_id);
Defensive patterns

Strategy: validation

Validate before calling

// Check the field name exists among registered descriptors before annotating:
// after static init, for row type T:
SpacetimeDB::field_registrar<T>::register_fields();
auto& descs = SpacetimeDB::get_table_descriptors();
// verify a field named 'id' exists for typeid(T) before adding ST_UNIQUE(T,"...","id")

Prevention

When it happens

Trigger: Renaming a struct member without updating the constraint macro's field string; passing the database column name when the descriptor uses the C++ member name (or vice versa); whitespace/typo differences in the quoted field name; constraining a field that exists only in a different type than T.

Common situations: Schema refactors where the member is renamed (e.g. userId -> user_id) but constraint annotations keep the old string; macro-generated field names that differ from expectations; copy-paste of constraint macros between similar tables.

Related errors


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