@@ -78,7 +78,14 @@ func (injector *Injector) Shutdown() {
7878
7979// Invoke will execute the parameter function (which must be a function that optionally can return an error).
8080// argument of function will be resolved by the injector using configured providers & scope.
81- func (injector * Injector ) Invoke (ctx context.Context , function any ) error {
81+ func (injector * Injector ) Invoke (ctx context.Context , function any ) (err error ) {
82+ // recover from potential panics in user code or reflection
83+ defer func () {
84+ if r := recover (); r != nil {
85+ err = fmt .Errorf ("panic during invocation: %v" , r )
86+ }
87+ }()
88+
8289 if function == nil {
8390 return newInvalidInputError ("can't invoke on nil" )
8491 }
@@ -89,6 +96,11 @@ func (injector *Injector) Invoke(ctx context.Context, function any) error {
8996 fmt .Sprintf ("can't invoke non-function %v (type %v)" , function , ftype ))
9097 }
9198
99+ // 2. check for Typed Nil, reflect.Call on a nil function value causes a panic.
100+ if fvalue .IsNil () {
101+ return newInvalidInputError (fmt .Sprintf ("can't invoke nil function %v" , ftype ))
102+ }
103+
92104 if ftype .NumOut () > 1 || (ftype .NumOut () == 1 && ! ftype .Out (0 ).AssignableTo (errorReflectType )) {
93105 return newInvalidInputError ("can't invoke on function whose return type is not error or no return type" )
94106 }
@@ -97,13 +109,27 @@ func (injector *Injector) Invoke(ctx context.Context, function any) error {
97109 if err != nil {
98110 return fmt .Errorf ("failed to call invokation function: %w" , err )
99111 }
100- if ftype .NumOut () == 1 {
101- invokationError := res [0 ].Interface ().(error )
102- if invokationError != nil {
103- return fmt .Errorf ("invokation returned error: %w" , invokationError )
104- }
112+ if ftype .NumOut () == 0 {
113+ return nil
105114 }
106- return nil
115+
116+ // check slice access
117+ if len (res ) == 0 {
118+ return fmt .Errorf ("function expected to return error but reflection result was empty" )
119+ }
120+
121+ val := res [0 ].Interface ()
122+ // handle the case where the interface is nil (no error returned)
123+ if val == nil {
124+ return nil
125+ }
126+
127+ // Assert it is an error
128+ if invokationError , ok := val .(error ); ok {
129+ return fmt .Errorf ("invokation returned error: %w" , invokationError )
130+ }
131+ // fallback for edge cases where AssignableTo passed but assertion failed
132+ return fmt .Errorf ("return value was not an error interface: %v" , val )
107133}
108134
109135func (injector * Injector ) eagerlyCreateSingletons () error {
0 commit comments