TypeError: You provided an invalid object where a stream was expected. You can provide an Observable, Promise, Array, or Iterable
AngularTypescriptRxjsObservableAngular Problem Overview
I am trying to map
from a service call but getting an error.
Looked at https://stackoverflow.com/questions/41995647/subscribe-is-not-defined-in-angular-2 and it said that in order to subscribe we need to return from inside the operators. I have return statements as well.
Here's my code:
checkLogin(): Observable<boolean> {
return this.service
.getData()
.map(
(response) => {
this.data = response;
this.checkservice = true;
return true;
},
(error) => {
// debugger;
this.router.navigate(["newpage"]);
console.log(error);
return false;
}
)
.catch((e) => {
return e;
});
}
Error log:
> TypeError: You provided an invalid object where a stream was expected. You can provide an Observable, Promise, Array, or Iterable
Angular Solutions
Solution 1 - Angular
In my case the error occurred only during e2e tests. It was caused by throwError
in my AuthenticationInterceptor.
I imported it from a wrong source because I used WebStorm's import feature. I am using RxJS 6.2.
Wrong:
import { throwError } from 'rxjs/internal/observable/throwError';
Correct:
import { throwError } from 'rxjs';
Here the full code of the interceptor:
import { Injectable } from '@angular/core';
import { HttpErrorResponse, HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http';
import { Observable, throwError } from 'rxjs';
import { catchError } from 'rxjs/operators';
@Injectable()
export class AuthenticationInterceptor implements HttpInterceptor {
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const reqWithCredentials = req.clone({withCredentials: true});
return next.handle(reqWithCredentials)
.pipe(
catchError(error => {
if (error.status === 401 || error.status === 403) {
// handle error
}
return throwError(error);
})
);
}
}
Solution 2 - Angular
In your example code, you have your map
operator receiving two callbacks, when it should only be receiving one. You can move your error handling code to your catch callback.
checkLogin():Observable<boolean>{
return this.service.getData()
.map(response => {
this.data = response;
this.checkservice=true;
return true;
})
.catch(error => {
this.router.navigate(['newpage']);
console.log(error);
return Observable.throw(error);
})
}
You'll need to also import the catch
and throw
operators.
import 'rxjs/add/operator/catch';
import 'rxjs/add/observable/throw';
EDIT:
Note that by returning Observable.throw
in your catch handler, you won't actually capture the error - it will still surface to the console.
Solution 3 - Angular
If your function is expecting to return a boolean, just do this:
- Import:
import { of, Observable } from 'rxjs';
import { map, catchError } from 'rxjs/operators';
- Then
checkLogin(): Observable<boolean> {
return this.service.getData()
.pipe(
map(response => {
this.data = response;
this.checkservice = true;
return true;
}),
catchError(error => {
this.router.navigate(['newpage']);
console.log(error);
return of(false);
})
)}
Solution 4 - Angular
You are returning an Observable
.map(response => <boolean>response.json())
If you are using another common service checkservice
in your case, you can simply use
this.service.getData().subscribe(data=>console.log(data));
This will make your checkLogin()
function with return type as void
checkLogin():void{
this.service.getData()
.map(response => {
this.data = response;
this.checkservice=true;
}).subscribe(data=>{ });
and you can use of this.checkService
to check your condition
Solution 5 - Angular
I was forgetting to return the other observable in pipe(switchMap(
this.dataService.getPerson(personId).pipe(
switchMap(person => {
//this.dataService.getCompany(person.companyId); // return missing
return this.dataService.getCompany(person.companyId);
})
)
Solution 6 - Angular
I had the same issue caused by importing the internal version of 'takeUntil' instead of the operators Change
import { takeUntil } from 'rxjs/internal/operators/takeUntil';
to
import { takeUntil } from 'rxjs/operators';
This happen also for other operators
Solution 7 - Angular
I've had this error when there's been different RxJS-versions across projects. The internal checks in RxJS fails because there are several different Symbol_observable
. Eventually this function throws once called from a flattening operator like switchMap
.
Try importing symbol-observable in some entry point.
// main index.ts
import 'symbol-observable';
Solution 8 - Angular
,
) in an RxJS pipe(...)
Can be triggered by a stray comma (The compile won't catch this extra comma at the end:
pipe(first(), map(result => ({ event: 'completed', result: result}),);
It becomes an 'invisible' undefined
operator which screws the whole pipe up, and leads to a very confusing error message - which in this case has nothing to do with my actual logic.
Solution 9 - Angular
I have been facing this issue when trying to authenticate a user using JSON Web Token. in my case it's related to authentication interceptor.
Sending a request to authenticate a user doesn't have to provide a token since it doesn't exist yet.
Check that your interceptor include this:
if (req.headers.get('No-Auth') == "True")
return next.handle(req.clone());
And that you provide {'No-Auth':'True'}
to your header's request like this:
authenticateUser(user): Observable<any> {
const headers = new HttpHeaders({'No-Auth':'True'});
headers.append('Content-Type', 'application/json');
return this.httpClient.post(`${this.apiEndpoint}/auth/authenticate`, user, {headers: headers});
}
Solution 10 - Angular
I wrote this because I arrive here searching for the same error, and this could be useful for someone in the future.
I get the same error while trying to initialize a service variable from its constructor making a call to a remote API trough http.get and .subscribe()
After many tests without understanding what the problem was, i finally get it: My application had authentication and an HttpInterceptor, and i was trying to initialize the service calling a public API method using http.get(...) without 'No-Auth' headers. I added them like here, and problem solved for me:
getData() {
var reqHeader = new HttpHeaders({ 'Content-Type': 'application/x-www-urlencoded','No-Auth':'True' });
return this.http.get(environment.urlApi.Literales, { headers: reqHeader });
}
What a headache :(
Solution 11 - Angular
A hint for anyone experiencing this. This can happen when a switchMap
doesn't receive an observable return value (like null). Simply add a default case, so it always returns an observable.
switchMap((dateRange) => {
if (dateRange === 'Last 24 hours') {
return $observable1;
}
if (dateRange === 'Last 7 Days') {
return $observable2;
}
if (dateRange === 'Last 30 Days') {
return $observable3;
}
// This line will work for default cases
return $observableElse;
})
Solution 12 - Angular
In my case in Angular-5, service file was not imported from which i was accessing the method and subscribing the data.After importing service file it worked fine.
Solution 13 - Angular
this error happened with me when i am using interceptor you have to do this in your interceptor
return next.handle(request).map(event => {
if (event instanceof HttpResponse) {
}
return event;
},
catchError((error: HttpErrorResponse) => {
if (error.status === 401 || error.status === 400) {
// some logic
}
Solution 14 - Angular
This error happened to me @angular 7
> You provided an invalid object where a stream was expected. You can provide an Observable, Promise, Array, or Iterable.
The error is actually self-explanatory, it says somewhere
in the observable I pass the invalid object. In my case, there was lots of API call but all the calls were failing because of wrong server configuration. I tried to use map
, switchMap
, or other rxjs operator but the operators are getting undefined objects.
So double-check your rxjs operator inputs.
Solution 15 - Angular
I was also facing the same issue when i was calling a method inside switchMap, apparently I found that if we use method inside switchMap it must return observable.
i used pipe to return observable and map to perform operations inside pipe for an api call which i was doing inside method rather than subscribing to it.
Solution 16 - Angular
I'm not sure if this will help anyone, but in my case further up my chain I was using distinctUntilChanged
and an exception inside a function there was manifesting with this error message.
Solution 17 - Angular
You will get the following error message too when you provide undefined or so to an operator which expects an Observable, eg. takeUntil.
TypeError: You provided an invalid object where a stream was expected. You can provide an Observable, Promise, Array, or Iterable
Solution 18 - Angular
In my case I mistakely imported Action into my combineEpics, rather than Epic...
Verify all the functions within combine Epics are epic funcitons
Solution 19 - Angular
I had a similar error using RXJS in NESTJS.
Error: TypeError: You provided 'undefined' where a stream was expected. You can provide an Observable, Promise, Array, or Iterable. +1ms
In my case I forgot to return an Observable in a switchMap. This caused that no Observable was received in the next RXJS operator or client code.
Once I returned an Observable in the switchMap, the error disappeared.
Solution 20 - Angular
I have the same exact error message while I was doing my unit test and throwing observable exception after mocking my services.
I resolved it by passing exact function and format inside Observable.throw
.
Actual code which calls the service and subscribe
to get data. notice that catch
to handle the 400
error.
this.search(event).catch((e: Response) => {
if (e.status === 400) {
console.log(e.json().message);
} else if (e.url) {
console.log('HTTP Error: ' + e.status + ' ' + e.statusText,
'URL: ' + e.url, 'Info: ' + e.json().message));
}
}).finally(() => {
this.loading = false;
}).subscribe((bData) => {
this.data = bData;
});
The code inside the service
search() {
return this.someService.getData(request)
.do((r) => {
this.someService.defaultHeaders.delete('skipAlert');
return r;
})
.map((r) => {
return r.businessObjectDataElements.length && r.businessObjectDataElements || null;
});
}
###Unit Testing
I have mocked the SomeService and returning observable data and its fine as it have all the required methods inside it.
someServiceApi = fixture.debugElement.injector.get(SomeService);
spyOn(someServiceApi, 'getData').and.returnValue(Observable.of({}));
The above code is okey but when when I was trying to test the catch/error condition by passing Observable.throw({})
it was showing me the error as it was expecting Response
type return from the service.
So below service mocking return was giving me that error.
someServiceApi.getData
.and.returnValue(Observable.throw(new Response({status: 400, body: [], message: 'not found error'})));
So I Corrected it by replicating the exact expected function in my return object rather passing a Response
type value.
someServiceApi.getData
.and.returnValue(Observable.throw({status: 400, json: () => { return {message: 'not found error'}}, body: []}));
// see `json: () => { return {message: 'not found error'}}` inside return value
Solution 21 - Angular
In regard to the "You provided an invalid object where a stream was expected. You can provide an Observable, Promise, Array, or Iterable" error.
This could happen if you import { Observable } from 'rxjs'
after (below) some module/function/whatever, which actually uses it.
Solution: move this import above the import of that module.