@@ -620,9 +620,9 @@ function completeValueCatchingError(
620
620
result: mixed
621
621
): mixed {
622
622
// If the field type is non-nullable, then it is resolved without any
623
- // protection from errors.
623
+ // protection from errors, however it still properly locates the error .
624
624
if ( returnType instanceof GraphQLNonNull ) {
625
- return completeValue (
625
+ return completeValueWithLocatedError (
626
626
exeContext ,
627
627
returnType ,
628
628
fieldASTs ,
@@ -635,7 +635,7 @@ function completeValueCatchingError(
635
635
// Otherwise, error protection is applied, logging the error and resolving
636
636
// a null value for this field if one is encountered.
637
637
try {
638
- const completed = completeValue (
638
+ const completed = completeValueWithLocatedError (
639
639
exeContext ,
640
640
returnType ,
641
641
fieldASTs ,
@@ -644,8 +644,8 @@ function completeValueCatchingError(
644
644
result
645
645
) ;
646
646
if ( isThenable ( completed ) ) {
647
- // If `completeValue ` returned a rejected promise, log the rejection
648
- // error and resolve to null.
647
+ // If `completeValueWithLocatedError ` returned a rejected promise, log
648
+ // the rejection error and resolve to null.
649
649
// Note: we don't rely on a `catch` method, but we do expect "thenable"
650
650
// to take a second callback for the error case.
651
651
return ( ( completed : any ) : Promise < * > ) . then ( undefined , error => {
@@ -655,13 +655,43 @@ function completeValueCatchingError(
655
655
}
656
656
return completed ;
657
657
} catch ( error ) {
658
- // If `completeValue ` returned abruptly (threw an error), log the error
659
- // and return null.
658
+ // If `completeValueWithLocatedError ` returned abruptly (threw an error),
659
+ // log the error and return null.
660
660
exeContext . errors . push ( error ) ;
661
661
return null ;
662
662
}
663
663
}
664
664
665
+ // This is a small wrapper around completeValue which annotates errors with
666
+ // location information.
667
+ function completeValueWithLocatedError(
668
+ exeContext: ExecutionContext,
669
+ returnType: GraphQLType,
670
+ fieldASTs: Array< Field > ,
671
+ info: GraphQLResolveInfo,
672
+ path: Array< string | number > ,
673
+ result: mixed
674
+ ): mixed {
675
+ try {
676
+ const completed = completeValue (
677
+ exeContext ,
678
+ returnType ,
679
+ fieldASTs ,
680
+ info ,
681
+ path ,
682
+ result
683
+ ) ;
684
+ if ( isThenable ( completed ) ) {
685
+ return ( ( completed : any ) : Promise < * > ) . catch (
686
+ error => Promise . reject ( locatedError ( error , fieldASTs , path ) )
687
+ ) ;
688
+ }
689
+ return completed ;
690
+ } catch (error) {
691
+ throw locatedError ( error , fieldASTs , path ) ;
692
+ }
693
+ }
694
+
665
695
/**
666
696
* Implements the instructions for completeValue as defined in the
667
697
* "Field entries" section of the spec.
@@ -694,23 +724,20 @@ function completeValue(
694
724
// If result is a Promise, apply-lift over completeValue.
695
725
if ( isThenable ( result ) ) {
696
726
return ( ( result : any ) : Promise < * > ) . then (
697
- // Once resolved to a value, complete that value.
698
727
resolved => completeValue (
699
728
exeContext ,
700
729
returnType ,
701
730
fieldASTs ,
702
731
info ,
703
732
path ,
704
733
resolved
705
- ) ,
706
- // If rejected, create a located error, and continue to reject.
707
- error => Promise . reject ( locatedError ( error , fieldASTs , path ) )
734
+ )
708
735
) ;
709
736
}
710
737
711
738
// If result is an Error, throw a located error.
712
739
if (result instanceof Error) {
713
- throw locatedError ( result , fieldASTs , path ) ;
740
+ throw result ;
714
741
}
715
742
716
743
// If field type is NonNull, complete for inner type, and throw field error
@@ -725,10 +752,9 @@ function completeValue(
725
752
result
726
753
) ;
727
754
if ( completed === null ) {
728
- throw new GraphQLError (
755
+ throw new Error (
729
756
`Cannot return null for non-nullable field ${
730
- info . parentType . name } .${ info . fieldName } .`,
731
- fieldASTs
757
+ info . parentType . name } .${ info . fieldName } .`
732
758
) ;
733
759
}
734
760
return completed ;
@@ -785,8 +811,7 @@ function completeValue(
785
811
}
786
812
787
813
// Not reachable. All possible output types have been considered.
788
- invariant(
789
- false,
814
+ throw new Error(
790
815
`Cannot complete value of unexpected type "${ String ( returnType ) } ".`
791
816
);
792
817
}
@@ -845,7 +870,13 @@ function completeLeafValue(
845
870
): mixed {
846
871
invariant ( returnType . serialize , 'Missing serialize method on type' ) ;
847
872
const serializedResult = returnType . serialize ( result ) ;
848
- return isNullish ( serializedResult ) ? null : serializedResult ;
873
+ if ( isNullish ( serializedResult ) ) {
874
+ throw new Error (
875
+ `Expected a value of type "${ String ( returnType ) } " but ` +
876
+ `received: ${ String ( result ) } `
877
+ ) ;
878
+ }
879
+ return serializedResult ;
849
880
}
850
881
851
882
/**
0 commit comments