apache/superset · error · KeyValueCreateFailedError

Unable to encode value

Error message

Unable to encode value

What it means

Raised by KeyValueDAO.create_entry when codec.encode(value) throws for any reason. The key-value store is generic: callers pick a KeyValueCodec (e.g. JsonCodec, PickleCodec) per resource, and if the value is not serializable by that codec the encode step fails and is wrapped in KeyValueCreateFailedError ('Unable to encode value'). Typical cause: JSON codec receiving a value containing datetime, Decimal, set, or arbitrary objects.

Source

Thrown at superset/daos/key_value.py:116

    ) -> KeyValueEntry:
        """
        Create a new entry in the key-value store.

        .. note::
            This method intentionally does **not** purge expired entries. Callers
            that pass an explicit ``key`` along with an ``expires_on`` must call
            :meth:`delete_expired_entries` for the same ``resource`` once before
            creating their entries. Purging is deliberately hoisted out of this
            method so that a transaction creating many entries pays the cleanup cost
            only once up front rather than on every insert. An expired entry still
            occupying the same ``key`` would otherwise cause this insert to fail the
            unique constraint. (Entries created without an explicit ``key`` get an
            auto-generated id and cannot collide, so they need no prior purge.)
        """
        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

View on GitHub (pinned to f4587218dd)

Solutions

  1. Inspect the exception's __cause__ (the original codec exception) to see exactly which value failed to encode.
  2. Convert non-serializable values before storing: str()/float() for datetimes and Decimals, or add a custom json.JSONEncoder default handler.
  3. Pick a codec that matches your data: PickleCodec for rich Python objects, JsonCodec only for plain JSON-safe structures.
  4. Add a unit test that round-trips your payload through codec.encode/decode before wiring it into KeyValueDAO.

Example fix

# before
KeyValueDAO.create_entry(resource, value={'ts': datetime.now()}, codec=JsonCodec())
# -> KeyValueCreateFailedError('Unable to encode value')

# after
from json import JSONEncoder
class SafeEncoder(JSONEncoder):
    def default(self, o):
        if isinstance(o, (datetime, date)):
            return o.isoformat()
        return super().default(o)
value = json.loads(json.dumps(value, cls=SafeEncoder))
KeyValueDAO.create_entry(resource, value=value, codec=JsonCodec())
Defensive patterns

Strategy: validation

Validate before calling

import json
from datetime import date, datetime
from decimal import Decimal

def json_safe(value):
    return json.loads(json.dumps(value, default=lambda o: o.isoformat() if isinstance(o, (datetime, date)) else str(o)))

# use: KeyValueDAO.create_entry(resource, json_safe(payload), JsonCodec())

Type guard

def is_json_safe(v: object) -> bool:
    try:
        json.dumps(v)
        return True
    except TypeError:
        return False

Try / catch

from superset.daos.key_value import KeyValueDAO
from superset.key_value.commands.exceptions import KeyValueCreateFailedError
try:
    entry = KeyValueDAO.create_entry(resource, value, codec, key=key)
except KeyValueCreateFailedError as err:
    cause = err.__cause__  # original codec exception — inspect it
    log.warning('encode failed: %r', cause)

Prevention

When it happens

Trigger: Storing chart/dashboard tab state or any payload containing datetime.datetime or Decimal objects through a JsonCodec-based resource; storing ORM model instances or numpy types with a codec that cannot pickle them; a custom codec whose encode() raises on unexpected input shapes.

Common situations: Chart data payloads built from pandas/sqlalchemy rows that carry Decimal or Timestamp values; switching a resource's codec (pickle -> json) without migrating stored-value expectations; frontend tab state containing non-JSON-serializable values injected server-side.

Related errors


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