clockworklabs/SpacetimeDB · error
ERROR: No field descriptors found for table %s
Error message
ERROR: No field descriptors found for table %s
What it means
After AddFieldConstraint calls SpacetimeDB::field_registrar<T>::register_fields(), it looks up the field descriptor map by &typeid(T). If T never produced descriptors, the lookup fails and the constraint is dropped with this message. In practice it means the template type T used by the constraint macro is not (the same type identity as) the row type whose fields were registered for the table.
Source
Thrown at crates/bindings-cpp/include/spacetimedb/internal/v9_builder.h:447
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
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", View on GitHub (pinned to 524b4487d9)
Solutions
- Ensure the constraint macro receives the exact row struct type that the table macro used, spelled identically in both places
- Confirm the row struct contains its field registration macro (field_registrar specialization) so register_fields populates descriptors
- Avoid typedef/alias indirection for row types in constraint registrations
- If the table is templated, check that no cv/reference qualifications leak into T before the typeid lookup
Example fix
// before — constraint registered for a different type identity using UserRow = User; ST_UNIQUE_ON_TYPE(UserRow, "users", id); // typeid(UserRow) may not match // after ST_UNIQUE_ON_TYPE(User, "users", id); // same type as the table registration
Defensive patterns
Strategy: validation
Validate before calling
// Assert descriptors exist for the exact row type before/after registration:
#include <spacetimedb/spacetimedb.h> // provides get_table_descriptors
bool HasDescriptorsFor(const std::type_index& ti) {
return SpacetimeDB::get_table_descriptors().count(ti.operator()) != 0; // adapt to API shape
} Prevention
- Spell the row type identically at the table and constraint sites — no typedefs or aliases
- Include the field registration macro in every row struct
- Beware cv/reference-qualified template instantiations changing typeid
When it happens
Trigger: Passing a wrapper/alias/base type instead of the actual row struct to the constraint macro; register_fields registering descriptors under a different type identity than typeid(T> (cv-qualified or typedef-diverged instantiations); the row type's field_registrar specialization missing because the type lacks the required field registration macro.
Common situations: Using a typedef or using-alias for the row type in one file so typeid differs; templated table helpers where T is deduced as a reference/const-qualified variant; splitting table definition and constraint macros across headers compiled with different type spellings; forgetting the field-registration macro inside the struct.
Related errors
- ERROR: Table '%s' not found when trying to add constraint to
- ERROR: Field '%s' not found in table '%s'
- Unknown constraint type
- ERROR: Skipping multi-column index registration '%s.%s' beca
- ERROR: Skipping default-value registration '%s.%s' because c
AI-assisted analysis of clockworklabs/SpacetimeDB@524b4487d9 (2026-08-16).
Data as JSON: /api/errors/dc2bb0c8d957c403.
Report an issue: GitHub.