diff --git a/expr_test.go b/expr_test.go index fd1ce3ab..4a34f0c4 100644 --- a/expr_test.go +++ b/expr_test.go @@ -1586,6 +1586,14 @@ func TestExpr_fetch_from_func(t *testing.T) { assert.Contains(t, err.Error(), "cannot fetch Value from func()") } +func TestExpr_fetch_field_from_string(t *testing.T) { + // Accessing a named field on a string value (via dynamic map lookup) should + // produce a clear error instead of "invalid operation: int(string)". + _, err := expr.Eval(`let v = {"k": "hello"}; v.k.missing != ""`, nil) + assert.Error(t, err) + assert.Contains(t, err.Error(), "cannot fetch missing from string") +} + func TestExpr_map_default_values(t *testing.T) { env := map[string]any{ "foo": map[string]string{}, diff --git a/vm/runtime/runtime.go b/vm/runtime/runtime.go index bc6f2b4d..529fbdee 100644 --- a/vm/runtime/runtime.go +++ b/vm/runtime/runtime.go @@ -42,6 +42,9 @@ func Fetch(from, i any) any { switch v.Kind() { case reflect.Array, reflect.Slice, reflect.String: + if _, ok := i.(string); ok { + panic(fmt.Sprintf("cannot fetch %v from %T", i, from)) + } index := ToInt(i) l := v.Len() if index < 0 {