# Buggy code
def callback(self, output, inputs=[], state=[]):
    self._validate_callback(output, inputs, state)

    callback_id = _create_callback_id(output)
    multi = isinstance(output, (list, tuple))

    self.callback_map[callback_id] = {
        "inputs": [
            {"id": c.component_id, "property": c.component_property} for c in inputs
        ],
        "state": [
            {"id": c.component_id, "property": c.component_property} for c in state
        ],
    }

    def wrap_func(func):
        @wraps(func)
        def add_context(*args, **kwargs):
            # don't touch the comment on the next line - used by debugger
            output_value = func(*args, **kwargs)  # %% callback invoked %%
            if multi:
                if not isinstance(output_value, (list, tuple)):
                    raise exceptions.InvalidCallbackReturnValue(
                        "The callback {} is a multi-output.\n"
                        "Expected the output type to be a list"
                        " or tuple but got {}.".format(callback_id, repr(output_value))
                    )

                if not len(output_value) == len(output):
                    raise exceptions.InvalidCallbackReturnValue(
                        "Invalid number of output values for {}.\n"
                        " Expected {} got {}".format(
                            callback_id, len(output), len(output_value)
                        )
                    )

                component_ids = collections.defaultdict(dict)
                has_update = False
                for i, o in enumerate(output):
                    val = output_value[i]
                    if val is not no_update:
                        has_update = True
                        o_id, o_prop = o.component_id, o.component_property
                        component_ids[o_id][o_prop] = val

                if not has_update:
                    raise exceptions.PreventUpdate

                response = {"response": component_ids, "multi": True}
            else:
                if output_value is no_update:
                    raise exceptions.PreventUpdate

                response = {
                    "response": {"props": {output.component_property: output_value}}
                }

            try:
                jsonResponse = json.dumps(response, cls=plotly.utils.PlotlyJSONEncoder)
            except TypeError:
                self._validate_callback_output(output_value, output)
                raise exceptions.InvalidCallbackReturnValue(
                    dedent(
                        """
                    The callback for property `{property:s}`
                    of component `{id:s}` returned a value
                    which is not JSON serializable.

                    In general, Dash properties can only be
                    dash components, strings, dictionaries, numbers, None,
                    or lists of those.
                    """
                    ).format(
                        property=output.component_property,
                        id=output.component_id,
                    )
                )

            return jsonResponse

        self.callback_map[callback_id]["callback"] = add_context

        return add_context

    return wrap_func


# Traceback (TypeError)
Exception on /_dash-update-component [POST]
Traceback (most recent call last):
File "/home/kz/Envs/dash_bleedingedge/lib/python3.7/site-packages/dash/dash.py", line 1328, in add_context
response, cls=plotly.utils.PlotlyJSONEncoder
File "/home/kz/.local/pyenv/versions/3.7.3/lib/python3.7/json/__init__.py", line 238, in dumps
**kw).encode(obj)
File "/home/kz/Envs/dash_bleedingedge/lib/python3.7/site-packages/_plotly_utils/utils.py", line 44, in encode
encoded_o = super(PlotlyJSONEncoder, self).encode(o)
File "/home/kz/.local/pyenv/versions/3.7.3/lib/python3.7/json/encoder.py", line 199, in encode
chunks = self.iterencode(o, _one_shot=True)
File "/home/kz/.local/pyenv/versions/3.7.3/lib/python3.7/json/encoder.py", line 257, in iterencode
return _iterencode(o, 0)
File "/home/kz/Envs/dash_bleedingedge/lib/python3.7/site-packages/_plotly_utils/utils.py", line 113, in default
return _json.JSONEncoder.default(self, obj)
File "/home/kz/.local/pyenv/versions/3.7.3/lib/python3.7/json/encoder.py", line 179, in default
raise TypeError(f'Object of type {o.__class__.__name__} '
TypeError: Object of type _NoUpdate is not JSON serializable

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "/home/kz/Envs/dash_bleedingedge/lib/python3.7/site-packages/flask/app.py", line 2446, in wsgi_app
response = self.full_dispatch_request()
File "/home/kz/Envs/dash_bleedingedge/lib/python3.7/site-packages/flask/app.py", line 1951, in full_dispatch_request
rv = self.handle_user_exception(e)
File "/home/kz/Envs/dash_bleedingedge/lib/python3.7/site-packages/flask/app.py", line 1820, in handle_user_exception
reraise(exc_type, exc_value, tb)
File "/home/kz/Envs/dash_bleedingedge/lib/python3.7/site-packages/flask/_compat.py", line 39, in reraise
raise value
File "/home/kz/Envs/dash_bleedingedge/lib/python3.7/site-packages/flask/app.py", line 1949, in full_dispatch_request
rv = self.dispatch_request()
File "/home/kz/Envs/dash_bleedingedge/lib/python3.7/site-packages/flask/app.py", line 1935, in dispatch_request
return self.view_functions[rule.endpoint](**req.view_args)
File "/home/kz/Envs/dash_bleedingedge/lib/python3.7/site-packages/dash/dash.py", line 1404, in dispatch
response.set_data(self.callback_map[output]["callback"](*args))
File "/home/kz/Envs/dash_bleedingedge/lib/python3.7/site-packages/dash/dash.py", line 1331, in add_context
self._validate_callback_output(output_value, output)
File "/home/kz/Envs/dash_bleedingedge/lib/python3.7/site-packages/dash/dash.py", line 1187, in _validate_callback_output
_validate_value(output_value)
File "/home/kz/Envs/dash_bleedingedge/lib/python3.7/site-packages/dash/dash.py", line 1180, in _validate_value
toplevel=True,
File "/home/kz/Envs/dash_bleedingedge/lib/python3.7/site-packages/dash/dash.py", line 1125, in _raise_invalid
bad_val=bad_val,
dash.exceptions.InvalidCallbackReturnValue:
The callback for `<Output `approot.children`>`
returned a value having type `_NoUpdate`
which is not JSON serializable.

The value in question is either the only value returned,
or is in the top level of the returned list,
and has string representation
`<dash.dash._NoUpdate object at 0x7ff2ca37ccf8>`

In general, Dash properties can only be
dash components, strings, dictionaries, numbers, None,
or lists of those.

# Fixed code
def callback(self, output, inputs=[], state=[]):
    self._validate_callback(output, inputs, state)

    callback_id = _create_callback_id(output)
    multi = isinstance(output, (list, tuple))

    self.callback_map[callback_id] = {
        "inputs": [
            {"id": c.component_id, "property": c.component_property} for c in inputs
        ],
        "state": [
            {"id": c.component_id, "property": c.component_property} for c in state
        ],
    }

    def wrap_func(func):
        @wraps(func)
        def add_context(*args, **kwargs):
            # don't touch the comment on the next line - used by debugger
            output_value = func(*args, **kwargs)  # %% callback invoked %%
            if multi:
                if not isinstance(output_value, (list, tuple)):
                    raise exceptions.InvalidCallbackReturnValue(
                        "The callback {} is a multi-output.\n"
                        "Expected the output type to be a list"
                        " or tuple but got {}.".format(callback_id, repr(output_value))
                    )

                if not len(output_value) == len(output):
                    raise exceptions.InvalidCallbackReturnValue(
                        "Invalid number of output values for {}.\n"
                        " Expected {} got {}".format(
                            callback_id, len(output), len(output_value)
                        )
                    )

                component_ids = collections.defaultdict(dict)
                has_update = False
                for i, o in enumerate(output):
                    val = output_value[i]
                    if not isinstance(val, _NoUpdate):
                        has_update = True
                        o_id, o_prop = o.component_id, o.component_property
                        component_ids[o_id][o_prop] = val

                if not has_update:
                    raise exceptions.PreventUpdate

                response = {"response": component_ids, "multi": True}
            else:
                if isinstance(output_value, _NoUpdate):
                    raise exceptions.PreventUpdate

                response = {
                    "response": {"props": {output.component_property: output_value}}
                }

            try:
                jsonResponse = json.dumps(response, cls=plotly.utils.PlotlyJSONEncoder)
            except TypeError:
                self._validate_callback_output(output_value, output)
                raise exceptions.InvalidCallbackReturnValue(
                    dedent(
                        """
                    The callback for property `{property:s}`
                    of component `{id:s}` returned a value
                    which is not JSON serializable.

                    In general, Dash properties can only be
                    dash components, strings, dictionaries, numbers, None,
                    or lists of those.
                    """
                    ).format(
                        property=output.component_property,
                        id=output.component_id,
                    )
                )

            return jsonResponse

        self.callback_map[callback_id]["callback"] = add_context

        return add_context

    return wrap_func