cube-js/cube · error · minijinja::Error

Unable to convert Map to Python object: key must be string,

Error message

Unable to convert Map to Python object: key must be string, actual: {}

What it means

When converting a MiniJinja `Map` to a Python object, every key must be a string. `from_minijinja_value` reads each key and, if `key.as_str()` is `None`, raises this error including the actual key kind. Python object (dict) keys are expected to be strings in this bridge.

Source

Thrown at packages/cubejs-backend-native/src/template/mj_value/python.rs:83

        }
        mjv::ValueKind::Map => {
            let mut obj = CLReprObject::new(if from.is_kwargs() {
                CLReprObjectKind::KWargs
            } else {
                CLReprObjectKind::Object
            });

            for key in from.try_iter()? {
                let value = if let Ok(v) = from.get_item(&key) {
                    from_minijinja_value(&v)?
                } else {
                    CLRepr::Null
                };

                let key_str = if let Some(key) = key.as_str() {
                    key.to_string()
                } else {
                    return Err(mj::Error::new(
                        mj::ErrorKind::InvalidOperation,
                        format!(
                            "Unable to convert Map to Python object: key must be string, actual: {}",
                            key.kind()
                        ),
                    ));
                };

                obj.insert(key_str, value);
            }

            Ok(CLRepr::Object(obj))
        }
        other => Err(mj::Error::new(
            mj::ErrorKind::InvalidOperation,
            format!("Converting from {:?} to Python is not supported", other),
        )),
    }

View on GitHub (pinned to 7d981676b3)

Solutions

  1. Convert keys to strings in the template: use `|string` on keys when constructing the map.
  2. Key the map by string loop variables (`loop.index | string`) instead of raw integers.
  3. Restructure the data as a sequence of objects if keys are inherently numeric.
  4. Handle the conversion in Python from a JSON string instead of a map value.

Example fix

// before
{% set m = {loop.index: item} %}
// after
{% set m = {loop.index.__string__(): item} %}  {# or build with string keys #}
Defensive patterns

Strategy: validation

Validate before calling

// in Jinja, ensure map keys are strings:
{% set m = {} %}{% for k, v in data %}{% set _ = m.update({k | string: v}) %}{% endfor %}

Type guard

fn map_keys_all_strings(v: &serde_json::Map<String, serde_json::Value>) -> bool { true } // enforce at map construction

Prevention

When it happens

Trigger: A template passes a map with non-string keys (e.g. integer keys like `{1: 'a'}`) into a Python filter, method call, or as a nested value during conversion.

Common situations: Building dicts in Jinja with numeric keys from loops (`{i: value}` inside a for loop), JSON objects produced with numeric keys, or merging maps keyed by indices.

Related errors


AI-assisted analysis of cube-js/cube@7d981676b3 (2026-09-02). Data as JSON: /api/errors/ba871ba481d218f4. Report an issue: GitHub.