diff --git a/scripts/fiber/tests-failing.txt b/scripts/fiber/tests-failing.txt
index 6c068aab0d..cc5e8e4bb0 100644
--- a/scripts/fiber/tests-failing.txt
+++ b/scripts/fiber/tests-failing.txt
@@ -83,7 +83,7 @@ src/renderers/shared/hooks/__tests__/ReactHostOperationHistoryHook-test.js
src/renderers/shared/shared/__tests__/ReactComponent-test.js
* should throw on invalid render targets
-* throws usefully when rendering badly-typed elements
+* includes owner name in the error about badly-typed elements
src/renderers/shared/shared/__tests__/ReactComponentLifeCycle-test.js
* should carry through each of the phases of setup
diff --git a/scripts/fiber/tests-passing.txt b/scripts/fiber/tests-passing.txt
index c596a95630..7562b2881b 100644
--- a/scripts/fiber/tests-passing.txt
+++ b/scripts/fiber/tests-passing.txt
@@ -1221,6 +1221,7 @@ src/renderers/shared/shared/__tests__/ReactComponent-test.js
* should support new-style refs with mixed-up owners
* should call refs at the correct time
* fires the callback after a component is rendered
+* throws usefully when rendering badly-typed elements
src/renderers/shared/shared/__tests__/ReactComponentLifeCycle-test.js
* should not reuse an instance when it has been unmounted
diff --git a/src/renderers/shared/fiber/ReactFiber.js b/src/renderers/shared/fiber/ReactFiber.js
index 9c3604a5f8..3b30d19cde 100644
--- a/src/renderers/shared/fiber/ReactFiber.js
+++ b/src/renderers/shared/fiber/ReactFiber.js
@@ -41,6 +41,8 @@ var {
NoEffect,
} = require('ReactTypeOfSideEffect');
+var invariant = require('invariant');
+
// A Fiber is work on a Component that needs to be done or was done. There can
// be more than one per component.
export type Fiber = {
@@ -315,7 +317,13 @@ function createFiberFromElementType(type : mixed, key : null | string) : Fiber {
// There is probably a clever way to restructure this.
fiber = ((type : any) : Fiber);
} else {
- throw new Error('Unknown component type: ' + typeof type);
+ invariant(
+ false,
+ 'Element type is invalid: expected a string (for built-in components) ' +
+ 'or a class/function (for composite components) but got: %s.',
+ type == null ? type : typeof type,
+ // TODO: Stack also includes owner name in the message.
+ );
}
return fiber;
}
diff --git a/src/renderers/shared/shared/__tests__/ReactComponent-test.js b/src/renderers/shared/shared/__tests__/ReactComponent-test.js
index cf73c7230c..e4e63281c3 100644
--- a/src/renderers/shared/shared/__tests__/ReactComponent-test.js
+++ b/src/renderers/shared/shared/__tests__/ReactComponent-test.js
@@ -347,4 +347,22 @@ describe('ReactComponent', () => {
expectDev(console.error.calls.count()).toBe(2);
});
+ it('includes owner name in the error about badly-typed elements', () => {
+ spyOn(console, 'error');
+
+ function Foo() {
+ var X = undefined;
+ return ;
+ }
+
+ expect(() => ReactTestUtils.renderIntoDocument()).toThrowError(
+ 'Element type is invalid: expected a string (for built-in components) ' +
+ 'or a class/function (for composite components) but got: undefined. ' +
+ 'Check the render method of `Foo`.'
+ );
+
+ // One warning for each element creation
+ expectDev(console.error.calls.count()).toBe(1);
+ });
+
});