Could someone help me figure out how to get a dash app running as a JupyterHub managed service? The error is in the dash-render api.js, which is pretty foreign to me. The toy app below runs fine when started from the console and accessed w/out JupyterHub. However, when I start up JupyterHub like so …
$ sudo jupyterhub -f /etc/jupyterhub/jupyterhub_config.py
where the config file contains …
c.JupyterHub.services = [
{
'name': 'hello-world',
'admin': False,
'url': 'http://127.0.0.1:8051',
'cwd': '/srv/hello-world',
'command': ['python', 'main.py', '--port', '8051'],
}
]
When I navigate to http://127.0.0.1:8000/services/hello-world
, it’s just “Error loading dependencies” and in the javascript console:
api.js:73 Error: Given action "SET_LAYOUT", reducer "layout" returned undefined. To ignore an action, you must explicitly return the previous state. If you want this reducer to hold no value, you can return null instead of undefined.
at combineReducers.js:123
at reducer.js:61
at reducer.js:101
at p (createStore.js:165)
at index.js:11
at e.value (APIController.react.js:47)
at e.value (APIController.react.js:29)
at p.updateComponent (react-dom.min.js:13)
at p.receiveComponent (react-dom.min.js:13)
at Object.receiveComponent (react-dom.min.js:14)
(anonymous) @ api.js:73
Promise.catch (async)
(anonymous) @ api.js:71
(anonymous) @ index.js:8
value @ APIController.react.js:44
value @ APIController.react.js:25
e.notifyAll @ react-dom.min.js:12
close @ react-dom.min.js:14
closeAll @ react-dom.min.js:15
perform @ react-dom.min.js:15
perform @ react-dom.min.js:15
perform @ react-dom.min.js:14
T @ react-dom.min.js:14
closeAll @ react-dom.min.js:15
perform @ react-dom.min.js:15
batchedUpdates @ react-dom.min.js:14
i @ react-dom.min.js:14
_renderNewRootComponent @ react-dom.min.js:14
_renderSubtreeIntoContainer @ react-dom.min.js:14
render @ react-dom.min.js:14
(anonymous) @ index.js:9
n @ bootstrap:19
(anonymous) @ transition.js:53
n @ bootstrap:19
(anonymous) @ bootstrap:83
(anonymous) @ bootstrap:83
api.js:73 TypeError: Cannot read property 'forEach' of undefined
at e.default (dependencyGraph.js:11)
at combineReducers.js:120
at reducer.js:61
at reducer.js:101
at p (createStore.js:165)
at index.js:11
at e.value (APIController.react.js:59)
at e.value (APIController.react.js:29)
at p.updateComponent (react-dom.min.js:13)
at p.receiveComponent (react-dom.min.js:13)
(anonymous) @ api.js:73
Promise.catch (async)
(anonymous) @ api.js:71
(anonymous) @ index.js:8
value @ APIController.react.js:54
value @ APIController.react.js:25
e.notifyAll @ react-dom.min.js:12
close @ react-dom.min.js:14
closeAll @ react-dom.min.js:15
perform @ react-dom.min.js:15
perform @ react-dom.min.js:15
perform @ react-dom.min.js:14
T @ react-dom.min.js:14
closeAll @ react-dom.min.js:15
perform @ react-dom.min.js:15
batchedUpdates @ react-dom.min.js:14
i @ react-dom.min.js:14
_renderNewRootComponent @ react-dom.min.js:14
_renderSubtreeIntoContainer @ react-dom.min.js:14
render @ react-dom.min.js:14
(anonymous) @ index.js:9
n @ bootstrap:19
(anonymous) @ transition.js:53
n @ bootstrap:19
(anonymous) @ bootstrap:83
(anonymous) @ bootstrap:83
Here’s /srv/hello-world/main.py
.
from os import environ
from argparse import ArgumentParser
from dash import Dash
import dash_html_components as tag
parser = ArgumentParser()
parser.add_argument('-p', '--port', default=8050)
args = parser.parse_args()
app = Dash(__name__)
app.layout = tag.Div('Hello, World!')
app.config.update({
'routes_pathname_prefix': '',
'requests_pathname_prefix': environ.get('JUPYTERHUB_SERVICE_PREFIX', '/'),
})
if __name__ == '__main__':
app.run_server(port=args.port)
As you can see, I’ve been guessing at the prefixes, but am really just taking shots in the dark here.