@@ -867,6 +867,8 @@ func TestSteps(t *testing.T) {
867867 t .Run ("NilReturnHandling" , func (t * testing.T ) {
868868 nilPointerReturn := func (ctx context.Context ) (* string , error ) { return nil , nil }
869869 nilInterfaceReturn := func (ctx context.Context ) (any , error ) { return nil , nil }
870+ nilConcreteReturn := func (ctx context.Context ) (string , error ) { return "" , nil } // Zero value, not nil
871+ trueNilNilReturn := func (ctx context.Context ) (interface {}, error ) { return nil , nil } // Both nil
870872
871873 // Test that nil pointers fail with type casting error (as expected)
872874 testWorkflowNilPointer := func (dbosCtx DBOSContext , input string ) (string , error ) {
@@ -917,6 +919,67 @@ func TestSteps(t *testing.T) {
917919 if result2 != "nil-interface-error-expected" {
918920 t .Fatalf ("expected result 'nil-interface-error-expected', got %q" , result2 )
919921 }
922+
923+ // Test concrete type with zero value (should work)
924+ t .Run ("ConcreteZeroValue" , func (t * testing.T ) {
925+ testWorkflowZeroValue := func (dbosCtx DBOSContext , input string ) (string , error ) {
926+ result , err := RunAsStep [string ](dbosCtx , nilConcreteReturn )
927+ if err != nil {
928+ return "zero-value-error" , err
929+ }
930+ return fmt .Sprintf ("zero-value-success: %q" , result ), nil
931+ }
932+ RegisterWorkflow (dbosCtx , testWorkflowZeroValue )
933+
934+ handle , err := RunAsWorkflow (dbosCtx , testWorkflowZeroValue , "input" )
935+ if err != nil {
936+ t .Fatal ("failed to run workflow with zero value:" , err )
937+ }
938+
939+ result , err := handle .GetResult ()
940+ if err != nil {
941+ t .Fatal ("failed to get result from zero value workflow:" , err )
942+ }
943+
944+ if result != "zero-value-success: \" \" " {
945+ t .Fatalf ("expected result 'zero-value-success: \" \" ', got %q" , result )
946+ }
947+ })
948+
949+ // Test true (nil, nil) return - both result and error are nil
950+ t .Run ("TrueNilNilReturn" , func (t * testing.T ) {
951+ testWorkflowNilNil := func (dbosCtx DBOSContext , input string ) (string , error ) {
952+ result , err := RunAsStep [interface {}](dbosCtx , trueNilNilReturn )
953+ if err != nil {
954+ // This is expected due to the type casting issue with nil interface{}
955+ if strings .Contains (err .Error (), "unexpected result type" ) {
956+ return "nil-nil-type-error-expected" , nil
957+ }
958+ return "nil-nil-other-error" , err
959+ }
960+ if result == nil {
961+ return "nil-nil-success: got nil result" , nil
962+ }
963+ return fmt .Sprintf ("nil-nil-unexpected: got %v" , result ), nil
964+ }
965+ RegisterWorkflow (dbosCtx , testWorkflowNilNil )
966+
967+ handle , err := RunAsWorkflow (dbosCtx , testWorkflowNilNil , "input" )
968+ if err != nil {
969+ t .Fatal ("failed to run workflow with nil-nil return:" , err )
970+ }
971+
972+ result , err := handle .GetResult ()
973+ if err != nil {
974+ t .Fatal ("failed to get result from nil-nil workflow:" , err )
975+ }
976+
977+ // This demonstrates that (nil, nil) with interface{} return causes type casting issues
978+ // This is a known limitation of the reflection-based approach
979+ if result != "nil-nil-type-error-expected" && result != "nil-nil-success: got nil result" {
980+ t .Fatalf ("expected 'nil-nil-type-error-expected' or success, got %q" , result )
981+ }
982+ })
920983 })
921984 })
922985
0 commit comments