{"record":{"id":"6004e543ed9d6e0e","repo":"kataras/iris","slug":"jetengine-addfunc-funcbody-argument-is-not-a-type","errorCode":null,"errorMessage":"JetEngine.AddFunc: funcBody argument is not a type of func(JetArguments) reflect.Value. Got %T instead","messagePattern":"JetEngine\\.AddFunc: funcBody argument is not a type of func\\(JetArguments\\) reflect\\.Value\\. Got %T instead","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"view/jet.go","lineNumber":171,"sourceCode":"\t\t\t// if has variadic.\n\n\t\t\tvariadicN := n - 1\n\t\t\tvariadicInputs := make([]any, variadicN) // except the first one.\n\n\t\t\tfor i := 0; i < variadicN; i++ {\n\t\t\t\tvariadicInputs[i] = args.Get(i + 1).Interface()\n\t\t\t}\n\n\t\t\treturn reflect.ValueOf(generalFunc(firstInput, variadicInputs...))\n\t\t}))\n\n\t\treturn\n\t}\n\n\tif jetFunc, ok := funcBody.(jet.Func); !ok {\n\t\talternativeJetFunc, ok := funcBody.(func(JetArguments) reflect.Value)\n\t\tif !ok {\n\t\t\tpanic(fmt.Sprintf(\"JetEngine.AddFunc: funcBody argument is not a type of func(JetArguments) reflect.Value. Got %T instead\", funcBody))\n\t\t}\n\n\t\ts.AddVar(funcName, jet.Func(alternativeJetFunc))\n\t} else {\n\t\ts.AddVar(funcName, jetFunc)\n\t}\n}\n\n// AddVar adds a global variable to the jet template set.\nfunc (s *JetEngine) AddVar(key string, value any) {\n\tif s.Set != nil {\n\t\ts.Set.AddGlobal(key, value)\n\t} else {\n\t\tif s.vars == nil {\n\t\t\ts.vars = make(map[string]any)\n\t\t}\n\t\ts.vars[key] = value\n\t}","sourceCodeStart":153,"sourceCodeEnd":189,"githubUrl":"https://github.com/kataras/iris/blob/7bedaf55a0b64bbb2248a5845a2c60d81a30996a/view/jet.go#L153-L189","documentation":"AddFunc only accepts jet.Func or func(JetArguments) reflect.Value. Passing any other Go function signature causes a panic via fmt.Sprintf describing the actual received type.","triggerScenarios":"Calling JetEngine.AddFunc(name, f) where f is e.g. func(string) string or func(...interface{}) reflect.Value instead of the two accepted forms.","commonSituations":"Reusing an ordinary helper function as a template function without wrapping it; migrating code from other template engines whose func signatures differ.","solutions":["Wrap the function: engine.AddFunc(\"name\", jet.Func(func(args jet.JetArguments) reflect.Value { ... }))","Or pass a value of type jet.Func directly","Match the required signature func(JetArguments) reflect.Value exactly"],"exampleFix":"// before\nengine.AddFunc(\"greet\", func(name string) string { return \"hi \" + name })\n// after\nengine.AddFunc(\"greet\", jet.Func(func(args jet.JetArguments) reflect.Value {\n    return reflect.ValueOf(\"hi \" + args.Get(0).String())\n}))","handlingStrategy":"type-guard","validationCode":"func isJetFunc(f any) bool {\n    switch f.(type) {\n    case jet.Func, func(view.JetArguments) reflect.Value:\n        return true\n    }\n    return false\n}","typeGuard":"func assertJetFunc(f any) (jet.Func, bool) {\n    if jf, ok := f.(jet.Func); ok { return jf, true }\n    if af, ok := f.(func(view.JetArguments) reflect.Value); ok { return jet.Func(af), true }\n    return nil, false\n}","tryCatchPattern":"defer func() { if r := recover(); r != nil { log.Printf(\"AddFunc panic: %v\", r) } }()\nengine.AddFunc(name, fn)","preventionTips":["Always wrap plain Go functions in jet.Func before AddFunc","Centralize template function registration in one helper that does the wrapping","Add a unit test registering every helper function used in templates"],"tags":["go","panic","type-mismatch","jet"],"backgroundTag":"invalid-callback-signature","analyzedSha":"7bedaf55a0b64bbb2248a5845a2c60d81a30996a","analyzedAt":"2026-08-30T20:38:16.250Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}