clockworklabs/SpacetimeDB · error

ERROR: Field %s.%s has auto_inc constraint - cannot have def

Error message

ERROR: Field %s.%s has auto_inc constraint - cannot have default value

What it means

AddColumnDefault refuses defaults on auto-incremented columns: it scans table->sequences and finds a sequence whose column == field_idx (registered earlier by the auto_inc/ST_AUTO_INC path), prints this message and returns, dropping the default. Auto-inc columns are populated by their sequence, so a serialized default would race the sequence generator.

Source

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

        }
    }
    
    // Check if this column has a unique constraint
    for (const auto& constraint : table->constraints) {
        if (constraint.data.get_tag() == 0) {  // Unique constraint variant
            const auto& unique_data = constraint.data.get<0>();
            if (unique_data.columns.size() == 1 && unique_data.columns[0] == field_idx) {
                fprintf(stderr, "ERROR: Field %s.%s has unique constraint - cannot have default value",
                        table_name.c_str(), field_name.c_str());
                return;
            }
        }
    }
    
    // Check if this column has an auto_inc sequence
    for (const auto& sequence : table->sequences) {
        if (sequence.column == field_idx) {
            fprintf(stderr, "ERROR: Field %s.%s has auto_inc constraint - cannot have default value",
                    table_name.c_str(), field_name.c_str());
            return;
        }
    }
    
    // Create the column default value structure
    RawColumnDefaultValueV9 col_default;
    col_default.table = table_name;
    col_default.col_id = field_idx;
    col_default.value = serialized_value;
    
    // Create the misc export entry with ColumnDefaultValue variant (variant 0)
    RawMiscModuleExportV9 export_entry;
    export_entry.set<0>(col_default);
    
    // Add to the module's misc_exports
    GetV9Module().misc_exports.push_back(export_entry);
}

View on GitHub (pinned to 524b4487d9)

Solutions

  1. Remove the column default from the auto-inc column — the sequence supplies values
  2. If a starting value is needed, set the sequence's min/start (as done in the sequence registration path) instead of a column default
  3. Rebuild and confirm the conflict message is gone

Example fix

// before
ST_AUTO_INC(order, id);
ST_COLUMN_DEFAULT(order, id, 1000);   // auto_inc + default
// after
ST_AUTO_INC(order, id);
// (default removed; configure the sequence start instead)
Defensive patterns

Strategy: validation

Validate before calling

// Policy check: refuse defaults on sequenced (auto_inc) columns
for (const auto& seq : table.sequences)
    if (seq.column == field_idx) /* forbid the ST_COLUMN_DEFAULT annotation */;

Prevention

When it happens

Trigger: A column annotated with both ST_AUTO_INC/auto_inc and ST_COLUMN_DEFAULT on the same table; the sequence registration ran first, so table->sequences contains the column when the default registration is validated.

Common situations: Adding a default to an id column that was already auto_inc; schema refactors merging annotations; porting from a SQL schema where DEFAULT nextval-style habits carried over.

Related errors


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