Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

You provided an invalid object where a stream was expected error in Module Federation environment #6628

Open
dragonflypl opened this issue Oct 4, 2021 · 5 comments

Comments

@dragonflypl
Copy link

Bug Report

Current Behavior

switchMap (and other mapping operators) might not work correctly in Module Federation environment.

Code like:

this
  .getSomeObservable()
  .pipe(
    switchMap(() => this.getOtherObservable()) // switching here causes the error
  ).subscribe()

Will cause : You provided an invalid object where a stream was expected error in Module Federation environment exception

Expected behavior

Mapping operators should work and recognise

Reproduction

I was not able yet to reproduce it with a repo I could publicly push. This is explanation from the app I'm maintaining.

I've migrated one app to MFE Architecture using Module Federation and mysteriously looking error is thrown at runtime:

You provided an invalid object where a stream was expected error. You can provide an Observable, Promise, Array, or Iterable.

The code that causes it looks like this:

this
  .getSomeObservable()
  .pipe(
    switchMap(() => this.getOtherObservable()) // switching here causes the error
  ).subscribe()

However I was pretty sure code was ok...

When analysing stack trace, error originates from:

https://github.com/ReactiveX/rxjs/blob/6.6.7/src/internal/util/subscribeTo.ts

export const subscribeTo = <T>(result: ObservableInput<T>): (subscriber: Subscriber<T>) => Subscription | void => {
  if (!!result && typeof result[Symbol_observable] === 'function') {
    return subscribeToObservable(result as any);
  } else if (isArrayLike(result)) {
    return subscribeToArray(result);
  } else if (isPromise(result)) {
    return subscribeToPromise(result as Promise<any>);
  } else if (!!result && typeof result[Symbol_iterator] === 'function') {
    return subscribeToIterable(result as any);
  } else {
    const value = isObject(result) ? 'an invalid object' : `'${result}'`;
    const msg = `You provided ${value} where a stream was expected.`
      + ' You can provide an Observable, Promise, Array, or Iterable.';
    throw new TypeError(msg);
  }
};

In my case, result is of type BehaviorSubject.

However, when I compared stack trace when app is running in non-federated to federated, the issue is here:

https://github.com/ReactiveX/rxjs/blob/6.6.7/src/internal/innerSubscribe.ts#L110

  if (result instanceof Observable) {
    return result.subscribe(innerSubscriber);
  }

Without module federation, this if is truthy, when I look at prototypes, deeper I can find Observable.

However in federated environment, this expression is falsy.

The good news it that refactoring to:

this
  .getSomeObservable()
  .subscribe(() => this.getOtherObservable().subscribe())

does not throw error any more.

Environment

@kwonoj
Copy link
Member

kwonoj commented Oct 4, 2021

This sounds like somewhat similar to other enviroment which crosses boundary such as worker, IPC, etcs than our instance check fails.

We didn't actively investigate to support webpack's module federation and do not have deep understanding around those yet. When webpack loads federated modules, does it properly passes over instance context across different modules? or otherwise, what exact observable object is being passed? if latter and if object is not proper instance of observable, what's webpack's contract for passing object across federated module?

I think figure out those would be helpful, and depends on how webpack treats object we may, or may not resolve problems on our end. For example, if webpack's federated module enforces to break some of core contract of observable (we expect to preserve our instance as-is, reason we do not gaurantee pass observabe across worker thread / processes, etcs) it'll be not easy to resolve without webpack's help.

@kwonoj
Copy link
Member

kwonoj commented Oct 4, 2021

But in any case, reproducible minimal example is strongly required to check futher.

@hgaleh
Copy link
Contributor

hgaleh commented Oct 31, 2021

I try to reproduce the error by the following code, However I fail. Can you suggest an alternative?
`
const obj = {

  obs1: of(1),

  obs2: of(2),

  func: function() {

    this.obs1

    .pipe(

      switchMap(() => this.obs2) // switching here causes the error

    ).subscribe();

  }

}

obj.func();

`

@ibis7
Copy link

ibis7 commented Feb 27, 2025

@dragonflypl were you ever able to identify what was the problem or a workaround that isn't removing switchMap? We are getting the same error in a micro-frontend context with Module Federation, but we started getting the error after we added a third-party script, so we're not sure if it's exactly the same problem, but apart from the third-party script part your problem is exactly the same.

@dragonflypl
Copy link
Author

@ibis7 it was long time ago, but as far as I remember, the issue was that operators code was not shared, e.g. one place imported switchMap operator from one node_modules dir, and some other place imported from other location.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants