invoke-ai/InvokeAI · error · ValueError

key does not match new_config.key

Error message

key does not match new_config.key

What it means

replace_model() overwrites an existing model record wholesale with new_config. To prevent accidentally re-keying a record, it requires that the `key` argument equals new_config.key; a mismatch means the caller is trying to replace one record with a config belonging to a different model, so ValueError is raised before any DB write.

Source

Thrown at invokeai/app/services/model_records/model_records_sql.py:227

                json_serialized = record.model_dump_json()

            cursor.execute(
                """--sql
                UPDATE models
                SET
                    config=?
                WHERE id=?;
                """,
                (json_serialized, key),
            )
            if cursor.rowcount == 0:
                raise UnknownModelException("model not found")

        return self.get_model(key)

    def replace_model(self, key: str, new_config: AnyModelConfig) -> AnyModelConfig:
        if key != new_config.key:
            raise ValueError("key does not match new_config.key")
        with self._db.transaction() as cursor:
            cursor.execute(
                """--sql
                UPDATE models
                SET
                    config=?
                WHERE id=?;
                """,
                (new_config.model_dump_json(), key),
            )
            if cursor.rowcount == 0:
                raise UnknownModelException("model not found")
        return self.get_model(key)

    def get_model(self, key: str) -> AnyModelConfig:
        """
        Retrieve the ModelConfigBase instance for the indicated model.

View on GitHub (pinned to 0b6a024f2f)

Solutions

  1. Set new_config.key = key (or build the new config from the fetched one so `.key` is preserved) before calling replace_model.
  2. Fetch the current config with get_model(key), copy() it, modify fields, and pass the copy back — its key stays consistent.
  3. If you actually want a new model entry, use add_model(new_config) instead of replace_model.
  4. Add an assertion comparing key == new_config.key early in your editing code to catch drift.

Example fix

// before
new_config = model_config.copy(update={"name": "new-name"})
records.replace_model(other_key, new_config)
// after
new_config = model_config.copy(update={"name": "new-name", "key": other_key})
records.replace_model(other_key, new_config)
Defensive patterns

Strategy: validation

Validate before calling

assert key == new_config.key, f"replace_model: {key!r} != {new_config.key!r}"
records.replace_model(key, new_config)

Type guard

def is_consistent_replace(key: str, cfg) -> bool:
    return getattr(cfg, "key", None) == key

Try / catch

try:
    records.replace_model(key, new_config)
except ValueError as e:
    if "key does not match" in str(e):
        new_config.key = key
        records.replace_model(key, new_config)

Prevention

When it happens

Trigger: Calling replace_model(existing_key, new_config) where new_config.key differs from existing_key — e.g. constructing a modified copy of a config without copying its `.key`, or passing a config loaded for a different model.

Common situations: Copying a model config object and editing fields but not preserving `.key`; passing a freshly built config (key None/default) instead of a fetched one; mixing up configs when batch-editing many models.

Related errors


AI-assisted analysis of invoke-ai/InvokeAI@0b6a024f2f (2026-08-29). Data as JSON: /api/errors/c24b01ec5ec043df. Report an issue: GitHub.