apache/superset · error · KeyValueCreateFailedError

An error occurred while creating the value.

Error message

An error occurred while creating the value.

What it means

Raised by KeyValueDAO.create_entry when an explicit key is supplied but assigning it to the entry raises ValueError. The assignment branches on type: UUID keys go to entry.uuid, anything else goes to entry.id; entry.id is an integer column, so a non-UUID, non-integer key (e.g. a random string) makes SQLAlchemy/psycopg raise ValueError, which is re-raised as KeyValueCreateFailedError ('An error occurred while creating the value.'). The message is the generic CreateFailedError default, distinct from the encode failure message.

Solutions

  1. Match the key type to the resource schema: pass a uuid.UUID (e.g. uuid.uuid4()) for UUID-keyed resources, an int for integer-keyed resources.
  2. Do not pass arbitrary string keys; if you need namespaced keys, store them as part of the encoded value or add a dedicated column.
  3. Inspect the exception's __cause__ to confirm the ValueError came from key assignment, then fix the key type at the call site.
  4. When creating entries with explicit keys and an expires_on, first call KeyValueDAO.delete_expired_entries for that resource as the docstring requires, so unique-constraint collisions on the same key do not surface as a different create failure.

Example fix

# before
KeyValueDAO.create_entry(resource, value, codec, key='tab-abc123')
# -> ValueError wrapped in KeyValueCreateFailedError

# after
import uuid
KeyValueDAO.create_entry(resource, value, codec, key=uuid.uuid4())  # UUID-keyed resource
KeyValueDAO.create_entry(resource, value, codec, key=42)  # int-keyed resource
Defensive patterns

Strategy: type-guard

Validate before calling

from uuid import UUID

def valid_kv_key(key) -> bool:
    return isinstance(key, UUID) or isinstance(key, int)

Type guard

from uuid import UUID

def is_valid_kv_key(key: object) -> TypeGuard[UUID | int]:
    return isinstance(key, (UUID, int))

Try / catch

from superset.key_value.commands.exceptions import KeyValueCreateFailedError
try:
    KeyValueDAO.create_entry(resource, value, codec, key=key)
except KeyValueCreateFailedError as err:
    if isinstance(err.__cause__, ValueError):
        # key type mismatch with the resource's key column
        key = uuid.uuid4()  # or int per resource schema, then retry once

Prevention

When it happens

Trigger: Calling create_entry(key='my-string-key', ...) for a resource whose key column expects int or UUID; passing an int-like string that SQLAlchemy still rejects in the column assignment path; mixing key types between resources (UUID-keyed dashboard tabs vs int-keyed entries) and reusing the wrong key object.

Common situations: Building a new key-value resource and generating keys with get_random_string() instead of uuid4()/ints; refactoring a resource from int keys to UUID keys while old callers still pass strings; copy-pasting the explicit-key code path from a UUID resource into an int-keyed one.

Related errors


AI-assisted analysis of apache/superset@f4587218dd (2026-08-14). Data as JSON: /api/errors/ea9f97fef9206543. Report an issue: GitHub.

Appendix: source

Thrown at superset/daos/key_value.py:131

        try:
            encoded_value = codec.encode(value)
        except Exception as ex:
            raise KeyValueCreateFailedError("Unable to encode value") from ex
        entry = KeyValueEntry(
            resource=resource.value,
            value=encoded_value,
            created_on=datetime.now(),
            created_by_fk=get_user_id(),
            expires_on=expires_on,
        )
        if key is not None:
            try:
                if isinstance(key, UUID):
                    entry.uuid = key
                else:
                    entry.id = key
            except ValueError as ex:
                raise KeyValueCreateFailedError() from ex
        db.session.add(entry)
        return entry

    @staticmethod
    def upsert_entry(
        resource: KeyValueResource,
        value: Any,
        codec: KeyValueCodec,
        key: Key,
        expires_on: datetime | None = None,
    ) -> KeyValueEntry:
        """
        Update an existing entry or create it if it does not exist.

        Because this overwrites any existing entry for the key (expired or not), it
        does not require a prior :meth:`delete_expired_entries` call.
        """
        if entry := KeyValueDAO.get_entry(resource, key):

View on GitHub (pinned to f4587218dd)