BoundaryML/baml · error

unsupported map key type: %s

Error message

unsupported map key type: %s

What it means

encodeMap serializes Go maps into the cffi HostMapValue sent across the FFI boundary to the BAML runtime. Go maps can be keyed by many primitive kinds, but only the kinds with a corresponding HostMapEntry_XXXKey variant (string, int, bool, etc.) are supported. When a map key's reflect.Kind has no encoder case, this error is returned so the whole encoding fails fast rather than silently dropping data.

Source

Thrown at engine/language_client_go/baml_go/serde/encode.go:241

		switch key.Kind() {
		case reflect.String:
			// Go doesn't have enums, so we can't detect them here
			entries = append(entries, &cffi.HostMapEntry{
				Key:   &cffi.HostMapEntry_StringKey{StringKey: key.String()},
				Value: valueHolder,
			})
		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
			entries = append(entries, &cffi.HostMapEntry{
				Key:   &cffi.HostMapEntry_IntKey{IntKey: key.Int()},
				Value: valueHolder,
			})
		case reflect.Bool:
			entries = append(entries, &cffi.HostMapEntry{
				Key:   &cffi.HostMapEntry_BoolKey{BoolKey: key.Bool()},
				Value: valueHolder,
			})
		default:
			return nil, fmt.Errorf("unsupported map key type: %s", key.Kind())
		}
	}

	return &cffi.HostMapValue{
		Entries: entries,
	}, nil
}

// Helper function to encode map entries into a vector offset
func EncodeMapEntries(fields map[string]any, context string) ([]*cffi.HostMapEntry, error) {
	entries := make([]*cffi.HostMapEntry, 0, len(fields))
	// Build entries (order doesn't strictly matter, but need to build bottom-up)
	for k, v := range fields {
		key := k
		valueHolder, err := encodeValue(v)
		if err != nil {
			return nil, fmt.Errorf("encoding %s field '%s': %w", context, k, err)
		}

View on GitHub (pinned to bd85ce9dee)

Solutions

  1. Change the map key to a supported primitive: string, integer, or bool (e.g. map[string]T).
  2. If keys are floats, convert them to formatted strings (strconv.FormatFloat) before encoding.
  3. If keys are structs or pointers, derive a canonical string key (e.g. fmt.Sprintf or a serialized id) before passing to BAML.
  4. If the key kind genuinely should be supported, file an issue / add a case to encodeMap in engine/language_client_go/baml_go/serde/encode.go.

Example fix

// before
m := map[float64]any{1.5: "x"}
ctx.Encode(m)

// after
m := map[string]any{}
for k, v := range rawFloatMap {
    m[strconv.FormatFloat(k, 'f', -1, 64)] = v
}
ctx.Encode(m)
Defensive patterns

Strategy: validation

Validate before calling

func checkMapKeys(m any) error {
	rv := reflect.ValueOf(m)
	if rv.Kind() != reflect.Map {
		return fmt.Errorf("not a map")
	}
	for _, k := range rv.MapKeys() {
		switch k.Kind() {
		case reflect.String, reflect.Int, reflect.Int32, reflect.Int64, reflect.Bool:
		default:
			return fmt.Errorf("unsupported map key kind: %s", k.Kind())
		}
	}
	return nil
}

Type guard

func hasStringKeys(m any) bool {
	rv := reflect.ValueOf(m)
	return rv.Kind() == reflect.Map && rv.Type().Key().Kind() == reflect.String
}

Try / catch

entries, err := serde.EncodeMapEntries(ctx, fields)
if err != nil {
	return fmt.Errorf("encoding args failed: %w", err)
}

Prevention

When it happens

Trigger: Passing a map with an unsupported key type (e.g. map[float64]T, map[struct{...}]T, map[chan T]T, map[*T]T, or a custom named type whose underlying kind is unsupported) into any API that encodes arguments — e.g. a BAML function parameter, client registry value, or context encoded via encodeValue -> encodeMap.

Common situations: Developers using float keys parsed from JSON, struct or pointer keys used as composite map keys, or time.Time / custom types as map keys. Also seen after refactoring a map[string]T into a map[SomeEnum]T where the enum is not a supported string-backed kind.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


AI-assisted analysis of BoundaryML/baml@bd85ce9dee (2026-09-12). Data as JSON: /api/errors/330a3371fbb96ae5. Report an issue: GitHub.