Angular 4 - Http request error: You provided 'undefined' where a stream was expected

11,604

Solution 1

After a lot a lot of effort, I have managed to locate and fix the problem. The problem was that I have an authorization interceptor that is intercepting every request to add an Authorization header with a user access token.

Since the call I was trying to do didn't require a user access token, but an application access token (authenticate as application for public Http requests like register, forgot password etc.), I decided to chain the call to get the application access token and the call for the forgotten password and just pass the retrieved application access token to the forgotten password method in my service and set it in the Authorization header there. This code was all fine. The problem was that I had edited the interceptor to check wether there was an Authorization header present and if so do nothing and THAT was the cause of the bug.

Instead of doing nothing, I should have just returned the request, so it just gets executed without modifications to the header.

so instead of

intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        if(request.headers.get('Authorization') == null) {
          //Code to add Authorization header
          return next.handle(requestWithAuthHeader)
        }
}

I had to do the following:

intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        if(request.headers.get('Authorization') == null) {
          //Code to add Authorization header
          return next.handle(requestWithAuthHeader)
        } else {
          return next.handle(request);
        }
}

Otherwise the request gets intercepted and never executes because it doesn't get returned by the interceptor. The method in my component is subscribed to the result of the service method and thus expects an observable, but nothing ever gets returned because the request got intercepted and the interceptor noticed that an Authorization header was already present (set in the service) so decided to do nothing with the request.

This explains why I got the error stating that I had provided undefined while a stream (observable) was expected on the subscribe line in my component's method.

Solution 2

I had a very similar issue. It also ended up being a problem with an HTTP interceptor. I had an automatic deserialization function running on all responses with a particular API endpoint pattern. Responses which weren't instances of HTTPResponse ended up being eaten. Adding an else statement which returned the response untouched when not an instance of HTTPResponse solve the issue for me:

@Injectable()
export class DeserializerInterceptor implements HttpInterceptor {
  public intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    return next.handle(request).map(
      event => {
        if (event instanceof HttpResponse) {
          let response = event as HttpResponse<any>;
          // ... deserialization of response object
          return response;
        } else {
          return event; // ... adding this else statement fixed the `undefined` error.
        }
      }
    );
  }
}

(Removed error handling code, for clarity.)

Share:
11,604
Dennis
Author by

Dennis

I'm a driven software developer with a big interest in Android and iOS apps. On top of all the mobile development I also occupy myself with writing some Angular applications from time to time. Backend development, mainly with NodeJS, is also something that interests me. In my spare time I try to enjoy life to the fullest and learn new things. On the rainy days you can find me brainstorming/developing my own applications or reading about cryptocurrencies and their technology. On lazy days I'm just watching my favorite shows.

Updated on June 09, 2022

Comments

  • Dennis
    Dennis almost 2 years

    While trying to do a HTTP Post request I am receiving the following error:

    auth.service.ts?c694:156 Something went wrong requesting a new password, error message: You provided 'undefined' where a stream was expected. You can provide an Observable, Promise, Array, or Iterable.

    The Http request is preceded by another one, which works perfectly fine.

    My component calling the service:

    requestNewPassword(formInput: NgForm) {
         if(formInput.controls['email'].value != '')
          this.authService.getApplicationAccessToken()
          .mergeMap((response: IAuthAppResponse) => this.authService.requestNewPassword(formInput, response.access_token))
          .subscribe(response => {
            // Content removed for simplicity
          })
        }
    

    The service method throwing the error:

    public requestNewPassword(formData: NgForm, applicationAccessToken: string): Observable<any> {
          let headers = new HttpHeaders({
            'Authorization':'Bearer ' + applicationAccessToken
          });
          let email: string = formData.controls['email'].value;
          const body = {
            email: email
          };
    
          console.log('requestNewPassword call header: ' + headers.get('Authorization'));
          console.log('Email: ' + body.email);
    
          return this.http.post(this.baseUrl + '/api/user/password/forgot', body, {headers}).do(response => {
            console.log("New password was successfully sent to the e-mail adress");
          }).catch((error: HttpErrorResponse) => {
            console.log('Something went wrong requesting a new password, error message: ' + error.message);
            return Observable.throw(error);
          })
        }
    

    Whenever I enter an email in the form and submit, which in turn triggers the requestNewPassword method of the component, I receive the error mentioned above from the service.

    The header and email are logged correctly so I don't think there's anything with the data I am providing.

    Since I have no idea how to debug this, I thought it was a good idea to post this as a question on this incredible platform.

    Thanks in advance!

    Update

    I minimized the code in my component to narrow down the problem by not chaining the two HTTP requests but only call the second one, that is causing trouble.

    requestNewPassword(formInput: NgForm) {
          if(formInput.controls['email'].value != '')
          this.authService.requestNewPassword(formInput, "")
           .subscribe(response => {
             // Content removed for simplicity
           })
         }
    

    I now get a full stack trace:

    ERROR TypeError: You provided 'undefined' where a stream was expected. You can provide an Observable, Promise, Array, or Iterable.
        at Object.subscribeToResult (subscribeToResult.js?c011:74)
        at MergeMapSubscriber._innerSub (mergeMap.js?e2a2:132)
        at MergeMapSubscriber._tryNext (mergeMap.js?e2a2:129)
        at MergeMapSubscriber._next (mergeMap.js?e2a2:112)
        at MergeMapSubscriber.Subscriber.next (Subscriber.js?215e:89)
        at ScalarObservable._subscribe (ScalarObservable.js?d097:49)
        at ScalarObservable.Observable._trySubscribe (Observable.js?4e06:172)
        at ScalarObservable.Observable.subscribe (Observable.js?4e06:160)
        at MergeMapOperator.call (mergeMap.js?e2a2:87)
        at Observable.subscribe (Observable.js?4e06:157)
        at FilterOperator.call (filter.js?35ab:60)
        at Observable.subscribe (Observable.js?4e06:157)
        at MapOperator.call (map.js?c4af:56)
        at Observable.subscribe (Observable.js?4e06:157)
        at DoOperator.call (tap.js?7fa8:63)
        at Observable.subscribe (Observable.js?4e06:157)
        at CatchOperator.call (catchError.js?0867:79)
        at Observable.subscribe (Observable.js?4e06:157)
        at PasswordResetComponent.requestNewPassword (passwordReset.component.ts?c169:43)
        at Object.eval [as handleEvent] (PasswordResetComponent.html:7)
        at handleEvent (core.js?223c:13255)
        at callWithDebugContext (core.js?223c:14740)
        at Object.debugHandleEvent [as handleEvent] (core.js?223c:14327)
        at dispatchEvent (core.js?223c:9704)
        at eval (core.js?223c:12028)
        at SafeSubscriber.schedulerFn [as _next] (core.js?223c:4235)
        at SafeSubscriber.__tryOrUnsub (Subscriber.js?215e:238)
        at SafeSubscriber.next (Subscriber.js?215e:185)
        at Subscriber._next (Subscriber.js?215e:125)
        at Subscriber.next (Subscriber.js?215e:89)
        at EventEmitter.Subject.next (Subject.js?c1c6:55)
        at EventEmitter.emit (core.js?223c:4203)
        at NgForm.onSubmit (forms.js?ad57:5710)
        at Object.eval [as handleEvent] (PasswordResetComponent.html:7)
        at handleEvent (core.js?223c:13255)
        at callWithDebugContext (core.js?223c:14740)
        at Object.debugHandleEvent [as handleEvent] (core.js?223c:14327)
        at dispatchEvent (core.js?223c:9704)
        at eval (core.js?223c:10318)
        at HTMLFormElement.eval (platform-browser.js?023b:2614)
        at ZoneDelegate.invokeTask (zone.js?fad3:425)
        at Object.onInvokeTask (core.js?223c:4620)
        at ZoneDelegate.invokeTask (zone.js?fad3:424)
        at Zone.runTask (zone.js?fad3:192)
        at ZoneTask.invokeTask [as invoke] (zone.js?fad3:499)
        at invokeTask (zone.js?fad3:1540)
        at HTMLFormElement.globalZoneAwareCallback (zone.js?fad3:1566)
    

    Since this mentions the html, I will provide the html code aswell:

    <form class="custom_form" #requestNewPasswordForm="ngForm" (ngSubmit)="requestNewPassword(requestNewPasswordForm)">
        <label>E-mail</label>
        <input class="custom_input" type="email" class="inputfield form-control" ngModel name="email">
        <button class="btn btn-default" type="submit">
          Send
        </button>
    </form>
    
  • computeiro
    computeiro about 6 years
    Thank you, I had a problem similar to yours and your solution worked.