45

I've been learning Angular 4 and everything was going smoothly until I tried to implement catch handling in a service. I'm trying to use "rxjs" catch and throw but I've got an undefined function error in my console.

import { Injectable } from '@angular/core';
import { Http } from "@angular/http";
import { Observable } from 'rxjs/observable';
import 'rxjs/add/operator/catch';
import 'rxjs/add/observable/throw';
import { AppError } from "../app/common/app.error";
import { NotFoundError } from "../app/common/not-found-error";
import { BadInput } from "../app/common/bad-input";

@Injectable()
export class PostService {
  private url = "https://jsonplaceholder.typicode.com/posts";

  constructor(private http: Http) { }

 deletepost(post){
      // return this.http.delete(this.url + '/' + post.id)
      // Hard-coded id to test 404
      return this.http.delete(this.url + '/' + 93498)
        .catch((error: Response) => {
          console.log('error within catch is ' + Response)
          if(error.status === 404)
            return Observable.throw(new NotFoundError(error));

          return Observable.throw(new AppError(error));
        });
    }
}

This is the error message:

TypeError: __WEBPACK_IMPORTED_MODULE_2_rxjs_observable__["Observable"].throw is not a function. 
(In '__WEBPACK_IMPORTED_MODULE_2_rxjs_observable__["Observable"].throw(new 
__WEBPACK_IMPORTED_MODULE_6__app_common_not_found_error__["a" /* NotFoundError 
*/](error))', 
'__WEBPACK_IMPORTED_MODULE_2_rxjs_observable__["Observable"].throw' is 
undefined) — post.service.ts:42

I also have this warning in my browser:

./~/rxjs/Observable.js
There are multiple modules with names that only differ in casing.
This can lead to unexpected behavior when compiling on a filesystem with other case-semantic.
Use equal casing. Compare these module identifiers:
* /Users/nickgowdy/Desktop/Angular2/angular4 source code/hello-world/node_modules/rxjs/Observable.js
    Used by 14 module(s), i. e.
    /Users/nickgowdy/Desktop/Angular2/angular4 source code/hello-world/node_modules/@angular/core/@angular/core.es5.js
* /Users/nickgowdy/Desktop/Angular2/angular4 source code/hello-world/node_modules/rxjs/observable.js
    Used by 1 module(s), i. e.
    /Users/nickgowdy/Desktop/Angular2/angular4 source code/hello-world/node_modules/@ngtools/webpack/src/index.js!/Users/nickgowdy/Desktop/Angular2/angular4 source code/hello-world/src/services/post.service.ts
nick gowdy
  • 6,191
  • 25
  • 88
  • 157
  • 1
    Try importing `import { Observable } from 'rxjs/Observable';` with a capital "O" instead of `import { Observable } from 'rxjs/observable';` with a lowercase "o" and see if that makes any difference. – Alexander Staroselsky Aug 02 '17 at 16:25
  • @AlexanderStaroselsky Wow I can't believe that was the reason why. I didn't notice that it was higher case O because it doesn't match the naming convention of all the other imported dependencies. You should post this as the answer so I can mark it as correct. – nick gowdy Aug 02 '17 at 17:41
  • I've experienced the same thing, the error doesn't always make it clear. Mind if I put that as an answer so that other experiencing the issue may find a solution? – Alexander Staroselsky Aug 02 '17 at 17:44
  • @AlexanderStaroselsky Yeah go for it. Create an answer for this question and i'll mark it as correct. Thanks for your help. – nick gowdy Aug 02 '17 at 17:45

5 Answers5

127

The error There are multiple modules with names that only differ in casing. is indicating the wrong import is being targeted with how you are trying to use Observable.

The import should be with a capital "O" like:

import { Observable } from 'rxjs/Observable';

This will import the individual Observable operator, which be used in combination with operators such as catch or throw on created Observables.

import 'rxjs/add/operator/catch';
import 'rxjs/add/observable/throw';

To import the full Observable object you'd import it like this:

import { Observable } from 'rxjs/Rx'

Update:

With newer versions of RxJS (5.5+) operators such as map() and filter() can used as pipeable operators in combination with pipe() rather than chaining. They are imported such as:

import { filter, map, catchError } from 'rxjs/operators';

Keep in mind terms such as throw are reserved/key words in JavaScript so the RxJS throw operator is imported as:

import { _throw } from 'rxjs/observable/throw';

Update:

For newer versions of RxJS (6+), use this:

import { throwError } from 'rxjs';

and throw an error like this:

if (error.status === 404)
    return throwError( new NotFoundError(error) )
Dharman
  • 30,962
  • 25
  • 85
  • 135
Alexander Staroselsky
  • 37,209
  • 15
  • 79
  • 91
  • 2
    Importing the full Observable - import { Observable } from 'rxjs/Rx' - increases bundle size. From the docs: https://github.com/ReactiveX/rxjs To import only what you need by patching (this is useful for size-sensitive bundling): import { Observable } from 'rxjs/Observable'; import 'rxjs/add/observable/of'; import 'rxjs/add/operator/map'; – barakbd Nov 30 '17 at 22:49
  • 1
    Yes, `import { Observable } from 'rxjs/Rx';` can significantly add to the bundle size as it's importing the full `Observable` object. In most cases I'd argue it's just not needed, but I wanted to provide it as an option as each application is different and may need that kind of control. – Alexander Staroselsky Dec 01 '17 at 01:08
  • @AlexanderStaroselsky bless you man helped me a lot, whats the difference beween import {Observable} from "rxjs/Observable and import {Observable} from "rxjs because i had problem with Observable throw(error) it only worked when i removed /Observable at the end – valik Apr 12 '18 at 15:33
  • @valik Without the `/Observable` it sounds like you are likely importing the full Observable object that includes methods such as `throw`. Depending on your RxJS version, I'd recommend to avoid importing the full `Observable` object and instead utilize [Pipeable Operators](https://github.com/ReactiveX/rxjs/blob/master/doc/pipeable-operators.md). Angular has documentation demonstrating using RxJS including using [catchError](https://angular.io/guide/rx-library#error-handling) to handle errors. Importing the full `Observable` object brings in stuff you simply may not need. – Alexander Staroselsky Apr 12 '18 at 15:58
  • //import {Observable} from "rxjs/Observable"; import { Observable } from 'rxjs'; this are the two first doesnt work well with private handleError (error: HttpResponse | any) { console.error(error.ok || error); return Observable.throw(error.status); } – valik Apr 12 '18 at 16:17
  • was not able to observe the status code @AlexanderStaroselsky with first one , but i want to know how to use the first one handle error it simply did not work when i changed i was able to observe my errors – valik Apr 12 '18 at 16:18
  • 2
    `Observable.throw()` is NOT available for `import { Observable } from 'rxjs/Observable';` Methods like `throw()` are available on `Observable` when importing the full `Observable` object either through `import { Observable } from 'rxjs/Rx';` or simply `import { Observable } from 'rxjs';`. However you can `import { Observable } from 'rxjs/Observable';` then `import 'rxjs/add/observable/throw';` and it should work. Check this [StackBlitz](https://stackblitz.com/edit/angular-z1sm1u). I'd also recommend to create a new question to help resolve any specific issues you are having. – Alexander Staroselsky Apr 12 '18 at 16:30
  • I had to import both `import { Observable } from 'rxjs/Observable';` and `import 'rxjs/add/observable/throw';` to avoid the error message `rxjs observable.throw is not a function`. – Stephane Jun 02 '18 at 22:38
  • Thank you for sharing detailed information. In my case only **import 'rxjs/add/observable/throw';** didn't work. After that I tried both import line **import 'rxjs/add/observable/throw'; import { _throw } from 'rxjs/observable/throw';** and it works like a charm – Dinesh Gopal Chand Dec 02 '18 at 19:22
30

In RxJS 6, Observable.throw() is replaced by throwError() which operates very similarly to its predecessor. So, you can replace from Observable.throw(error) to only throwError(error) by importing:

import { throwError } from 'rxjs';

Checkout this link for further reference: https://www.metaltoad.com/blog/angular-6-upgrading-api-calls-rxjs-6

13

I was facing the same issue in my angular 5 application. What I did is, adding a new package.

import { throwError } from 'rxjs';
import { filter, map, catchError } from 'rxjs/operators';

And from my http service call I return a function.

return this.http.request(request)
      .pipe(map((res: Response) => res.json()),
        catchError((res: Response) => this.onError(res)));

And in onError function I am returning the error with throwError(error).

onError(res: Response) {
    const statusCode = res.status;
    const body = res.json();
    const error = {
      statusCode: statusCode,
      error: body.error
    };
    return throwError(error);
  }
Sibeesh Venu
  • 18,755
  • 12
  • 103
  • 140
  • 1
    This solution worked in my Angular 6 app w/ rxjs 6.0. My import statement is already import { Observable } from 'rxjs/Observable' , while doing this I still get the Observable.throw is not a function error. I tried import 'rxjs/add/observable/throw' but it gave a compiler error. – wctiger Jul 18 '18 at 15:12
  • 1
4

_throw has been discarded in newer versions of RxJS
For newer versions of RxJS (6+), use this:

 import { throwError } from 'rxjs'; 

and throw an error like this:

 if (error.status === 404)
    return throwError( new NotFoundError(error) )
Waleed Shahzaib
  • 1,526
  • 2
  • 18
  • 34
0

In Angular9 Observable:

  1. if data arrived and status is OK, then send the data
  2. If STATUS of the data is NOT OK, then throw an error
myObsFunc(): Observable<any> { 
  return this.http.get<any>('/api/something') 
    .pipe(
      /* Catch a backend error and let the component know */
      catchError( err => {
        /* Rethrow error */
        return throwError( err );
      }),
      map( (res)=> {
        if( res.STATUS == "OK" ) {
          /* Send DATA to subscriber */
          return Object.values( res.DATA)
        } else {
           /* Inform subscriber that a functional error occured */
           throw ( "getOrphans: Status is not OK but "+ res.STATUS ) ;
        }   
      }),
    )   
}
Rob Lassche
  • 841
  • 10
  • 16