Repository: dask/distributed

Issue:
`TypeError` in `ExceptionsTable.update`
https://github.com/dask/distributed/blob/main/distributed/dashboard/components/scheduler.py#L3293 fails if `ts.erred_on` is `None`.

```
Aug 11 13:40:51 ip-10-0-9-12 cloud-init[1262]: 2022-08-11 13:40:51,814 - bokeh.util.tornado - ERROR - Error thrown from periodic callback:
Aug 11 13:40:51 ip-10-0-9-12 cloud-init[1262]: 2022-08-11 13:40:51,816 - bokeh.util.tornado - ERROR - Traceback (most recent call last):
Aug 11 13:40:51 ip-10-0-9-12 cloud-init[1262]:   File "/opt/conda/envs/coiled/lib/python3.10/site-packages/tornado/gen.py", line 526, in callback
Aug 11 13:40:51 ip-10-0-9-12 cloud-init[1262]:     result_list.append(f.result())
Aug 11 13:40:51 ip-10-0-9-12 cloud-init[1262]:   File "/opt/conda/envs/coiled/lib/python3.10/site-packages/bokeh/server/session.py", line 95, in _needs_document_lock_wrapper
Aug 11 13:40:51 ip-10-0-9-12 cloud-init[1262]:     result = func(self, *args, **kwargs)
Aug 11 13:40:51 ip-10-0-9-12 cloud-init[1262]:   File "/opt/conda/envs/coiled/lib/python3.10/site-packages/bokeh/server/session.py", line 229, in with_document_locked
Aug 11 13:40:51 ip-10-0-9-12 cloud-init[1262]:     return func(*args, **kwargs)
Aug 11 13:40:51 ip-10-0-9-12 cloud-init[1262]:   File "/opt/conda/envs/coiled/lib/python3.10/site-packages/bokeh/document/callbacks.py", line 450, in wrapper
Aug 11 13:40:51 ip-10-0-9-12 cloud-init[1262]:     return invoke_with_curdoc(doc, invoke)
Aug 11 13:40:51 ip-10-0-9-12 cloud-init[1262]:   File "/opt/conda/envs/coiled/lib/python3.10/site-packages/bokeh/document/callbacks.py", line 408, in invoke_with_curdoc
Aug 11 13:40:51 ip-10-0-9-12 cloud-init[1262]:     return f()
Aug 11 13:40:51 ip-10-0-9-12 cloud-init[1262]:   File "/opt/conda/envs/coiled/lib/python3.10/site-packages/bokeh/document/callbacks.py", line 449, in invoke
Aug 11 13:40:51 ip-10-0-9-12 cloud-init[1262]:     return f(*args, **kwargs)
Aug 11 13:40:51 ip-10-0-9-12 cloud-init[1262]:   File "/opt/conda/envs/coiled/lib/python3.10/site-packages/distributed/dashboard/components/__init__.py", line 41, in <lambda>
Aug 11 13:40:51 ip-10-0-9-12 cloud-init[1262]:     doc.add_periodic_callback(lambda: update(ref), interval)
Aug 11 13:40:51 ip-10-0-9-12 cloud-init[1262]:   File "/opt/conda/envs/coiled/lib/python3.10/site-packages/bokeh/core/property/validation.py", line 95, in func
Aug 11 13:40:51 ip-10-0-9-12 cloud-init[1262]:     return input_function(*args, **kwargs)
Aug 11 13:40:51 ip-10-0-9-12 cloud-init[1262]:   File "/opt/conda/envs/coiled/lib/python3.10/site-packages/distributed/dashboard/components/__init__.py", line 49, in update
Aug 11 13:40:51 ip-10-0-9-12 cloud-init[1262]:     comp.update()
Aug 11 13:40:51 ip-10-0-9-12 cloud-init[1262]:   File "/opt/conda/envs/coiled/lib/python3.10/site-packages/bokeh/core/property/validation.py", line 95, in func
Aug 11 13:40:51 ip-10-0-9-12 cloud-init[1262]:     return input_function(*args, **kwargs)
Aug 11 13:40:51 ip-10-0-9-12 cloud-init[1262]:   File "/opt/conda/envs/coiled/lib/python3.10/site-packages/distributed/dashboard/components/scheduler.py", line 3293, in update
Aug 11 13:40:51 ip-10-0-9-12 cloud-init[1262]:     new_data["Worker(s)"].append(",\n".join(ts.erred_on))
Aug 11 13:40:51 ip-10-0-9-12 cloud-init[1262]: TypeError: sequence item 0: expected str instance, NoneType found
```

(https://cloud.coiled.io/dask-engineering/clusters/48659/details)


Discussion:

Resolving patch:
diff --git a/distributed/scheduler.py b/distributed/scheduler.py
--- a/distributed/scheduler.py
+++ b/distributed/scheduler.py
@@ -2259,7 +2259,7 @@ def transition_processing_released(self, key: str, stimulus_id: str):
                 assert ts.state == "processing"
 
             w = _remove_from_processing(self, ts)
-            if w:
+            if w in self.workers:
                 worker_msgs[w] = [
                     {
                         "op": "free-keys",
@@ -2304,7 +2304,6 @@ def transition_processing_erred(
         traceback=None,
         exception_text: str | None = None,
         traceback_text: str | None = None,
-        worker: str | None = None,
         **kwargs,
     ):
         ws: WorkerState
@@ -2329,7 +2328,7 @@ def transition_processing_erred(
 
             w = _remove_from_processing(self, ts)
 
-            ts.erred_on.add(w or worker)  # type: ignore
+            ts.erred_on.add(w)
             if exception is not None:
                 ts.exception = exception
                 ts.exception_text = exception_text  # type: ignore
@@ -7314,7 +7313,7 @@ def request_remove_replicas(
         )
 
 
-def _remove_from_processing(state: SchedulerState, ts: TaskState) -> str | None:
+def _remove_from_processing(state: SchedulerState, ts: TaskState) -> str:
     """Remove *ts* from the set of processing tasks.
 
     See also
@@ -7326,7 +7325,7 @@ def _remove_from_processing(state: SchedulerState, ts: TaskState) -> str | None:
     ts.processing_on = None
 
     if ws.address not in state.workers:  # may have been removed
-        return None
+        return ws.address
 
     duration = ws.processing.pop(ts)
     ws.long_running.discard(ts)


Test patch: