diff --git a/go.mod b/go.mod
index 1f94424c686dc81bb80569395734cae6eeddfb2b..8a4930530908ac3b9d4dca32bd63c6f2ad9fdad7 100644
--- a/go.mod
+++ b/go.mod
@@ -5,7 +5,7 @@ go 1.23.2
 require (
 	github.com/avast/retry-go/v4 v4.6.0
 	github.com/bep/gowebp v0.4.0
-	github.com/expr-lang/expr v1.16.9
+	github.com/expr-lang/expr v1.17.2
 	github.com/go-kit/kit v0.13.0
 	github.com/gosimple/slug v1.14.0
 	github.com/hashicorp/go-multierror v1.1.1
diff --git a/go.sum b/go.sum
index 4b2f278b81ef6999417ee78fb77df8203b8073db..eec324be4ef01738394ec0213717ae56c7ebdbb3 100644
--- a/go.sum
+++ b/go.sum
@@ -10,8 +10,8 @@ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ3
 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/expr-lang/expr v1.16.9 h1:WUAzmR0JNI9JCiF0/ewwHB1gmcGw5wW7nWt8gc6PpCI=
-github.com/expr-lang/expr v1.16.9/go.mod h1:8/vRC7+7HBzESEqt5kKpYXxrxkr31SaO8r40VO/1IT4=
+github.com/expr-lang/expr v1.17.2 h1:o0A99O/Px+/DTjEnQiodAgOIK9PPxL8DtXhBRKC+Iso=
+github.com/expr-lang/expr v1.17.2/go.mod h1:8/vRC7+7HBzESEqt5kKpYXxrxkr31SaO8r40VO/1IT4=
 github.com/go-kit/kit v0.13.0 h1:OoneCcHKHQ03LfBpoQCUfCluwd2Vt3ohz+kvbJneZAU=
 github.com/go-kit/kit v0.13.0/go.mod h1:phqEHMMUbyrCFCTgH48JueqrM3md2HcAZ8N3XE4FKDg=
 github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU=
diff --git a/pkg/expr/config.go b/pkg/expr/config.go
index 130342b812b8798bd5d94b564fd5f27296facff5..a079d76811095ab5f7fc143cafe79931799019cc 100644
--- a/pkg/expr/config.go
+++ b/pkg/expr/config.go
@@ -37,10 +37,6 @@ func GetDefaultConfig(e map[string]interface{}) *conf.Config {
 	return defaultConfig.GetConfig(e)
 }
 
-// func GetDefaultEnv(e map[string]interface{}) map[string]interface{} {
-//	return defaultConfig.GetEnv(e)
-// }
-
 func Extend(kv ...interface{}) expr.Option {
 	e := make(map[string]interface{})
 	i := 0
@@ -62,23 +58,19 @@ func Extend(kv ...interface{}) expr.Option {
 
 func ExtendMap(e map[string]interface{}) expr.Option {
 	return func(c *conf.Config) {
-		var env map[string]interface{}
-		var ok bool
-		if c.Env == nil {
-			env = make(map[string]interface{})
-		} else {
-			if env, ok = c.Env.(map[string]interface{}); !ok {
+		env := make(map[string]interface{})
+		if !c.Env.IsUnknown() {
+			var ok bool
+			if env, ok = c.EnvObject.(map[string]interface{}); !ok {
 				panic("only map expr environment is supported")
 			}
 		}
+
 		for k, v := range e {
 			if _, ok := env[k]; !ok {
 				env[k] = v
 			}
 		}
-		c.Strict = true
-		c.MapEnv = true
-		c.Env = env
-		c.Types = conf.CreateTypesTable(c.Env)
+		c.WithEnv(env)
 	}
 }
diff --git a/pkg/expr/expr.go b/pkg/expr/expr.go
index 42588c2b9b03cb28be7f52a6edcb18561271d347..5c438b60c54ba84ff2a66acd7f04c93138557107 100644
--- a/pkg/expr/expr.go
+++ b/pkg/expr/expr.go
@@ -28,14 +28,12 @@ func Eval(ctx context.Context, input string, env map[string]interface{}) (interf
 	e[EnvContextKey] = ctx
 	cfg := GetDefaultConfig(e)
 
-	env, _ = cfg.Env.(map[string]interface{})
-
 	program, err := exprcompiler.Compile(tree, cfg)
 	if err != nil {
 		return nil, err
 	}
 
-	output, err := vm.Run(program, env)
+	output, err := vm.Run(program, e)
 	if err != nil {
 		return nil, err
 	}
diff --git a/pkg/expr/format_test.go b/pkg/expr/format_test.go
index 7a0ba4c67e899c058372ca65e050f58e83ec0073..576a55eb2dca15dc24bdd38d7c9974f502c7f25c 100644
--- a/pkg/expr/format_test.go
+++ b/pkg/expr/format_test.go
@@ -19,7 +19,7 @@ func TestFormat(t *testing.T) {
 	}{
 		{"sprintf#1", "sprintf(s1, s2)", map[string]interface{}{"s1": "hello %s", "s2": "world"}, "hello world"},
 		{"sprintf#2", "sprintf(s1, s2)", map[string]interface{}{"s1": nil, "s2": nil}, ""},
-		{"sprintf#3", "sprintf(s1, s2)", map[string]interface{}{"s1": "hello %s", "s2": nil}, "hello %!s(<nil>)"},
+		{"sprintf#3", "sprintf(s1, s2)", map[string]interface{}{"s1": "hello %s", "s2": nil}, "hello []"},
 		{"to_upper#1", "to_upper(s1)", map[string]interface{}{"s1": "hello"}, "HELLO"},
 		{"to_upper#2", "to_upper(s1)", map[string]interface{}{"s1": nil}, ""},
 		{"trim_space#1", "trim_space(s1)", map[string]interface{}{"s1": " hel lo  wor ld  "}, "hel lo  wor ld"},
diff --git a/pkg/expr/mongo.go b/pkg/expr/mongo.go
index 5a503a7ee76eaa7a7d0197b955868a298b5fad73..6e189db8195a1b0a80d0c715ef53b335c5e546ac 100644
--- a/pkg/expr/mongo.go
+++ b/pkg/expr/mongo.go
@@ -62,7 +62,7 @@ func convertToMongo(ctx context.Context, config *MongoExprConfig, tree *parser.T
 		op(exprConfig)
 	}
 
-	env = exprConfig.Env.(map[string]interface{})
+	env, _ = exprConfig.EnvObject.(map[string]interface{})
 
 	c := &compiler{
 		tree:               tree,
@@ -135,8 +135,6 @@ func (c *compiler) compile(node ast.Node) interface{} {
 		return c.CallNode(n)
 	case *ast.BuiltinNode:
 		return c.BuiltinNode(n)
-	case *ast.ClosureNode:
-		return c.ClosureNode(n)
 	case *ast.PointerNode:
 		return c.PointerNode(n)
 	case *ast.ConditionalNode:
@@ -615,10 +613,6 @@ func (c *compiler) BuiltinNode(node *ast.BuiltinNode) interface{} {
 //	return size
 // }
 
-func (c *compiler) ClosureNode(node *ast.ClosureNode) interface{} {
-	return c.compile(node.Node)
-}
-
 func (c *compiler) PointerNode(node *ast.PointerNode) interface{} {
 	panic("unsupported pointer node")
 	// c.emit(OpLoad, c.makeConstant("array")...)