clockworklabs/SpacetimeDB · error

Original error: Multiple primary keys detected in table '%s'

Error message

Original error: Multiple primary keys detected in table '%s'

What it means

Detail line of the '[CONSTRAINT ERROR]' banner (error 666) that restates the root cause: multiple primary keys were detected in the named table (g_multiple_primary_key_table_name). It exists so the module-side stderr log carries the table name, since the server only sees the opaque ERROR_MULTIPLE_PRIMARY_KEYS_<table> error type.

Source

Thrown at crates/bindings-cpp/src/internal/Module.cpp:263

        // Create the error type name
        std::string error_type_name = "ERROR_MULTIPLE_PRIMARY_KEYS_" + g_multiple_primary_key_table_name;
        
        // Add a single named type export that points to a non-existent typespace index
        // This will cause SpacetimeDB to error when it tries to resolve the type
        RawTypeDefV10 error_type;
        error_type.source_name.scope = {};
        error_type.source_name.source_name = error_type_name;
        error_type.ty = 999999; // Invalid typespace index - will cause an error
        error_type.custom_ordering = false;
        
        getV10Builder().GetTypeDefs().push_back(error_type);
        
        // Don't add anything to the typespace - this ensures the reference is invalid
        // The server will fail with an error message that includes our error type name
        
        // Also log to stderr for debugging
        fprintf(stderr, "\n[CONSTRAINT ERROR] Module cleared and replaced with error type: %s\n", error_type_name.c_str());
        fprintf(stderr, "Original error: Multiple primary keys detected in table '%s'\n\n", g_multiple_primary_key_table_name.c_str());
        fflush(stderr);
        
        return; // Exit early, don't check type registration errors
    }

    if (g_constraint_registration_error) {
        getV10Builder().Clear();

        std::string error_type_name = "ERROR_CONSTRAINT_REGISTRATION_" + g_constraint_registration_error_code;
        for (char& c : error_type_name) {
            if (!std::isalnum(c) && c != '_') {
                c = '_';
            }
        }

        RawTypeDefV10 error_type;
        error_type.source_name.scope = {};
        error_type.source_name.source_name = error_type_name;

View on GitHub (pinned to 6dee26c6ef)

Solutions

  1. Open the table named on this line and keep a single FIELD_PrimaryKey/FIELD_PrimaryKeyAutoInc macro
  2. Convert the surplus primary-key column to FIELD_Unique or part of a multi-column index
  3. Republish and confirm the ERROR_MULTIPLE_PRIMARY_KEYS_* type no longer appears in the module description

Example fix

// before
FIELD_PrimaryKey(Session, id);
FIELD_PrimaryKey(Session, token);

// after
FIELD_PrimaryKey(Session, id);
FIELD_Unique(Session, token);
Defensive patterns

Strategy: validation

Prevention

When it happens

Trigger: Emitted together with error 666 whenever __preinit__99_validate_types finds g_multiple_primary_key_error set; the table named here is the one carrying two or more primary-key constraints.

Common situations: Same as error 661/666 - duplicated or composite primary-key macros on one table struct.

Related errors


AI-assisted analysis of clockworklabs/SpacetimeDB@6dee26c6ef (2026-08-20). Data as JSON: /api/errors/7b4dea1d575f7050. Report an issue: GitHub.