wavetermdev/waveterm · error

cannot convert %T to %s (key %s is not a map, is %T)

Error message

cannot convert %T to %s (key %s is not a map, is %T)

What it means

For map[string]waveobj.WaveObj arguments, every value in the JSON map must itself be a JSON object decodable as a WaveObj. This error identifies the failing key and the offending value's Go type, e.g. when a map value is a string, number, or nested array instead of a serialized WaveObj.

Source

Thrown at pkg/service/service.go:158

				return nil, fmt.Errorf("cannot convert %T to %s (idx %d is not a map, is %T)", jsonArg, waveObjSliceRType, idx, elem)
			}
			nativeObj, err := waveobj.FromJsonMap(elemMap)
			if err != nil {
				return nil, fmt.Errorf("cannot convert %T to %s (idx %d) error: %v", jsonArg, waveObjSliceRType, idx, err)
			}
			nativeSlice[idx] = nativeObj
		}
		return nativeSlice, nil
	} else if argType == waveObjMapRType {
		if jsonType.Kind() != reflect.Map {
			return nil, fmt.Errorf("cannot convert %T to %s", jsonArg, argType)
		}
		mapArg := jsonArg.(map[string]any)
		nativeMap := make(map[string]waveobj.WaveObj)
		for key, elem := range mapArg {
			elemMap, ok := elem.(map[string]any)
			if !ok {
				return nil, fmt.Errorf("cannot convert %T to %s (key %s is not a map, is %T)", jsonArg, waveObjMapRType, key, elem)
			}
			nativeObj, err := waveobj.FromJsonMap(elemMap)
			if err != nil {
				return nil, fmt.Errorf("cannot convert %T to %s (key %s) error: %v", jsonArg, waveObjMapRType, key, err)
			}
			nativeMap[key] = nativeObj
		}
		return nativeMap, nil
	} else {
		return nil, fmt.Errorf("invalid special wave argument type %s", argType)
	}
}

func convertSpecialForReturn(argType reflect.Type, nativeArg any) (any, error) {
	if argType == waveObjRType {
		return waveobj.ToJsonMap(nativeArg.(waveobj.WaveObj))
	} else if argType == waveObjSliceRType {
		nativeSlice := nativeArg.([]waveobj.WaveObj)

View on GitHub (pinned to a4447c1563)

Solutions

  1. Replace the value at the reported key with a full serialized WaveObj object.
  2. Resolve any orefs/IDs in the map to their full WaveObj JSON before the call.
  3. Validate every map value is a plain object client-side before invoking.
  4. Check for version skew between the caller and the service method's expected schema.

Example fix

// before
callService("objservice", "SetObjects", { "main": "block:default:abc" })
// after
callService("objservice", "SetObjects", { "main": await rpcGetWaveObjJson("block:default:abc") })
Defensive patterns

Strategy: validation

Validate before calling

for (const [k, v] of Object.entries(arg)) { if (!v || typeof v !== 'object' || Array.isArray(v)) throw new Error('map value at key ' + k + ' must be a serialized WaveObj object'); }

Type guard

const isWaveObjMapValue = (v) => typeof v === 'object' && v !== null && !Array.isArray(v) && typeof v.otype === 'string';

Try / catch

try { return await callService(svc, method, arg); } catch (e) { const m = String(e).match(/key (\S+) is not a map, is (\S+)/); if (m) { console.error('bad WaveObj map value at key', m[1], 'type', m[2]); } throw e; }

Prevention

When it happens

Trigger: An RPC call with a WaveObj map argument where at least one value is not an object — commonly map values that are oref strings, object IDs, or booleans.

Common situations: Clients sending {"key": "oref-string"} or {"key": "oid"} maps instead of full object payloads; migrating an endpoint from ID-maps to object-maps while old callers persist; template or dynamically-built payloads injecting the wrong value type for one key.

Related errors


AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01). Data as JSON: /api/errors/b9d2f5286504222c. Report an issue: GitHub.