diff --git a/ipykernel/iostream.py b/ipykernel/iostream.py
index 5c7f96e..dae05af 100644
--- a/ipykernel/iostream.py
+++ b/ipykernel/iostream.py
@@ -205,8 +205,6 @@ class OutStream(object):
             warnings.warn("pipe argument to OutStream is deprecated and ignored",
                 DeprecationWarning)
         self.encoding = 'UTF-8'
-        # This is necessary for compatibility with Python built-in streams
-        self.errors = None
         self.session = session
         if not isinstance(pub_thread, IOPubThread):
             # Backward-compat: given socket, not thread. Wrap in a thread.
diff --git a/ipykernel/zmqshell.py b/ipykernel/zmqshell.py
index b209ee6..cb17c70 100644
--- a/ipykernel/zmqshell.py
+++ b/ipykernel/zmqshell.py
@@ -68,7 +68,7 @@ class ZMQDisplayPublisher(DisplayPublisher):
     # thread_local:
     # An attribute used to ensure the correct output message
     # is processed. See ipykernel Issue 113 for a discussion.
-    thread_local = Any()
+    _thread_local = Any()
 
     def set_parent(self, parent):
         """Set the parent for outbound messages."""
@@ -79,14 +79,17 @@ class ZMQDisplayPublisher(DisplayPublisher):
         sys.stdout.flush()
         sys.stderr.flush()
 
-    @default('thread_local')
+    @default('_thread_local')
     def _default_thread_local(self):
-        """ Initialises the threadlocal attribute and
-            gives it a 'hooks' attribute.
-        """
-        loc = local()
-        loc.hooks = []
-        return loc
+        """Initialize our thread local storage"""
+        return local()
+
+    @property
+    def _hooks(self):
+        if not hasattr(self._thread_local, 'hooks'):
+            # create new list for a new thread
+            self._thread_local.hooks = []
+        return self._thread_local.hooks
 
     def publish(self, data, metadata=None, source=None):
         self._flush_streams()
@@ -108,7 +111,7 @@ class ZMQDisplayPublisher(DisplayPublisher):
         # Each transform either returns a new
         # message or None. If None is returned,
         # the message has been 'used' and we return.
-        for hook in self.thread_local.hooks:
+        for hook in self._hooks:
             msg = hook(msg)
             if msg is None:
                 return
@@ -143,7 +146,7 @@ class ZMQDisplayPublisher(DisplayPublisher):
         Returning `None` will halt that execution path, and
         session.send will not be called.
         """
-        self.thread_local.hooks.append(hook)
+        self._hooks.append(hook)
 
     def unregister_hook(self, hook):
         """
@@ -160,7 +163,7 @@ class ZMQDisplayPublisher(DisplayPublisher):
                found.
         """
         try:
-            self.thread_local.hooks.remove(hook)
+            self._hooks.remove(hook)
             return True
         except ValueError:
             return False

'thread._local' object has no attribute 'hooks'
I just installed the newest versions of ipython and GraphLab and noticed this error. Here is the relevant code and the traceback.

    # sales is an SFrame
    graphlab.canvas.set_target('ipynb')
    sales.show(view="Scatter Plot", x="CrimeRate", y="HousePrice")

Traceback:
```


AttributeErrorTraceback (most recent call last)
<ipython-input-7-6f077ba0dabb> in <module>()
      1 graphlab.canvas.set_target('ipynb')
----> 2 sales.show(view="Scatter Plot", x="CrimeRate", y="HousePrice")

/usr/local/lib/python2.7/site-packages/graphlab/data_structures/sframe.pyc in show(self, columns, view, x, y)
   4950             __LOGGER__.warn("Column selection for SFrame.show is deprecated. To show only certain columns, use the sf[['column1', 'column2']] syntax or construct a new SFrame with the desired columns.")
   4951         from ..visualization.show import show
-> 4952         show(self, view=view, x=x, y=y)
   4953 
   4954     def pack_columns(self, columns=None, column_prefix=None, dtype=list,

/usr/local/lib/python2.7/site-packages/multipledispatch/dispatcher.pyc in __call__(self, *args, **kwargs)
    162             self._cache[types] = func
    163         try:
--> 164             return func(*args, **kwargs)
    165 
    166         except MDNotImplementedError:

/usr/local/lib/python2.7/site-packages/graphlab/canvas/glc_display_dispatch.pyc in show(obj, **kwargs)
      8     import graphlab.canvas.views.sframe
      9     graphlab.canvas.inspect.find_vars(obj)
---> 10     return graphlab.canvas.show(graphlab.canvas.views.sframe.SFrameView(obj, params=kwargs))
     11 
     12 

/usr/local/lib/python2.7/site-packages/graphlab/canvas/utils.pyc in show(variable)
    129         get_target().state.set_selected_variable(variable)
    130         variable.validate_js_component_name(variable.get_js_component())
--> 131     return get_target().show()
    132 
    133 def _get_id(ref):

/usr/local/lib/python2.7/site-packages/graphlab/canvas/target.pyc in show(self, variable)
    175             IPython.core.display.Javascript(
    176                 data=self.__makeJS(_to_json(data), view.get_js_file(), view.get_js_component()),
--> 177                 css=['//cdnjs.cloudflare.com/ajax/libs/font-awesome/4.1.0/css/font-awesome.min.css', self.get_asset_url() + 'css/canvas.css']
    178             )
    179         )

/usr/local/lib/python2.7/site-packages/IPython/core/display.pyc in display_javascript(*objs, **kwargs)
    328         Metadata to be associated with the specific mimetype output.
    329     """
--> 330     _display_mimetype('application/javascript', objs, **kwargs)
    331 
    332 

/usr/local/lib/python2.7/site-packages/IPython/core/display.pyc in _display_mimetype(mimetype, objs, raw, metadata)
     74         # turn list of pngdata into list of { 'image/png': pngdata }
     75         objs = [ {mimetype: obj} for obj in objs ]
---> 76     display(*objs, raw=raw, metadata=metadata, include=[mimetype])
     77 
     78 #-----------------------------------------------------------------------------

/usr/local/lib/python2.7/site-packages/IPython/core/display.pyc in display(*objs, **kwargs)
    169                 # kwarg-specified metadata gets precedence
    170                 _merge(md_dict, metadata)
--> 171             publish_display_data(data=format_dict, metadata=md_dict)
    172 
    173 

/usr/local/lib/python2.7/site-packages/IPython/core/display.pyc in publish_display_data(data, metadata, source)
    119     InteractiveShell.instance().display_pub.publish(
    120         data=data,
--> 121         metadata=metadata,
    122     )
    123 

/usr/local/lib/python2.7/site-packages/ipykernel/zmqshell.pyc in publish(self, data, metadata, source)
    109         # message or None. If None is returned,
    110         # the message has been 'used' and we return.
--> 111         for hook in self.thread_local.hooks:
    112             msg = hook(msg)
    113             if msg is None:

AttributeError: 'thread._local' object has no attribute 'hooks'
```
diff --git a/ipykernel/tests/test_zmq_shell.py b/ipykernel/tests/test_zmq_shell.py
index 6743db6..8426fa2 100644
--- a/ipykernel/tests/test_zmq_shell.py
+++ b/ipykernel/tests/test_zmq_shell.py
@@ -5,7 +5,14 @@
 # Distributed under the terms of the Modified BSD License.
 
 import os
+try:
+    from queue import Queue
+except ImportError:
+    # py2
+    from Queue import Queue
+from threading import Thread
 import unittest
+
 from traitlets import Int
 import zmq
 
@@ -88,12 +95,24 @@ class ZMQDisplayPublisherTests(unittest.TestCase):
         self.assertEqual(self.disp_pub.session, self.session)
         self.assertEqual(self.disp_pub.pub_socket, self.socket)
 
-    def test_thread_local_default(self):
+    def test_thread_local_hooks(self):
         """
         Confirms that the thread_local attribute is correctly
         initialised with an empty list for the display hooks
         """
-        self.assertEqual(self.disp_pub.thread_local.hooks, [])
+        self.assertEqual(self.disp_pub._hooks, [])
+        def hook(msg):
+            return msg
+        self.disp_pub.register_hook(hook)
+        self.assertEqual(self.disp_pub._hooks, [hook])
+
+        q = Queue()
+        def set_thread_hooks():
+            q.put(self.disp_pub._hooks)
+        t = Thread(target=set_thread_hooks)
+        t.start()
+        thread_hooks = q.get(timeout=10)
+        self.assertEqual(thread_hooks, [])
 
     def test_publish(self):
         """

pip install -e .
parse_log_pytest
pytest
nose nose-warnings-filters pytest
3.5
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
attrs @ file:///opt/conda/conda-bld/attrs_1642510447205/work
backcall==0.2.0
certifi==2021.5.30
decorator==5.1.1
entrypoints==0.4
importlib-metadata @ file:///tmp/build/80754af9/importlib-metadata_1631916693255/work
iniconfig @ file:///home/linux1/recipes/ci/iniconfig_1610983019677/work
-e git+https://github.com/ipython/ipykernel.git@6c63f53000e07b7f4f8542501dc94b42578f1d15#egg=ipykernel
ipython==7.16.3
ipython-genutils==0.2.0
jedi==0.17.2
jupyter-client==7.1.2
jupyter-core==4.9.2
more-itertools @ file:///tmp/build/80754af9/more-itertools_1637733554872/work
nest-asyncio==1.6.0
nose==1.3.7
nose-warnings-filters==0.1.5
packaging @ file:///tmp/build/80754af9/packaging_1637314298585/work
parso==0.7.1
pexpect==4.9.0
pickleshare==0.7.5
pluggy @ file:///tmp/build/80754af9/pluggy_1615976315926/work
prompt-toolkit==3.0.36
ptyprocess==0.7.0
py @ file:///opt/conda/conda-bld/py_1644396412707/work
Pygments==2.14.0
pyparsing @ file:///tmp/build/80754af9/pyparsing_1635766073266/work
pytest==6.2.4
python-dateutil==2.9.0.post0
pyzmq==25.1.2
six==1.17.0
toml @ file:///tmp/build/80754af9/toml_1616166611790/work
tornado==6.1
traitlets==4.3.3
typing_extensions @ file:///opt/conda/conda-bld/typing_extensions_1647553014482/work
wcwidth==0.2.13
zipp @ file:///tmp/build/80754af9/zipp_1633618647012/work

name: ipykernel
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - attrs=21.4.0=pyhd3eb1b0_0
  - ca-certificates=2025.2.25=h06a4308_0
  - certifi=2021.5.30=py36h06a4308_0
  - importlib-metadata=4.8.1=py36h06a4308_0
  - importlib_metadata=4.8.1=hd3eb1b0_0
  - iniconfig=1.1.1=pyhd3eb1b0_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.3=he6710b0_2
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - more-itertools=8.12.0=pyhd3eb1b0_0
  - ncurses=6.4=h6a678d5_0
  - openssl=1.1.1w=h7f8727e_0
  - packaging=21.3=pyhd3eb1b0_0
  - pip=21.2.2=py36h06a4308_0
  - pluggy=0.13.1=py36h06a4308_0
  - py=1.11.0=pyhd3eb1b0_0
  - pyparsing=3.0.4=pyhd3eb1b0_0
  - pytest=6.2.4=py36h06a4308_2
  - python=3.6.13=h12debd9_1
  - readline=8.2=h5eee18b_0
  - setuptools=58.0.4=py36h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - toml=0.10.2=pyhd3eb1b0_0
  - typing_extensions=4.1.1=pyh06a4308_0
  - wheel=0.37.1=pyhd3eb1b0_0
  - xz=5.6.4=h5eee18b_1
  - zipp=3.6.0=pyhd3eb1b0_0
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - backcall==0.2.0
      - decorator==5.1.1
      - entrypoints==0.4
      - ipython==7.16.3
      - ipython-genutils==0.2.0
      - jedi==0.17.2
      - jupyter-client==7.1.2
      - jupyter-core==4.9.2
      - nest-asyncio==1.6.0
      - nose==1.3.7
      - nose-warnings-filters==0.1.5
      - parso==0.7.1
      - pexpect==4.9.0
      - pickleshare==0.7.5
      - prompt-toolkit==3.0.36
      - ptyprocess==0.7.0
      - pygments==2.14.0
      - python-dateutil==2.9.0.post0
      - pyzmq==25.1.2
      - six==1.17.0
      - tornado==6.1
      - traitlets==4.3.3
      - wcwidth==0.2.13
prefix: /opt/conda/envs/ipykernel

ipykernel/tests/test_zmq_shell.py::ZMQDisplayPublisherTests::test_thread_local_hooks
ipykernel/tests/test_zmq_shell.py::ZMQDisplayPublisherTests::test_display_hook_halts_send ipykernel/tests/test_zmq_shell.py::ZMQDisplayPublisherTests::test_display_hook_return_calls_send ipykernel/tests/test_zmq_shell.py::ZMQDisplayPublisherTests::test_display_publisher_creation ipykernel/tests/test_zmq_shell.py::ZMQDisplayPublisherTests::test_publish ipykernel/tests/test_zmq_shell.py::ZMQDisplayPublisherTests::test_unregister_hook
ipykernel/iostream.py ipykernel/zmqshell.py
ipykernel/iostream.py ipykernel/zmqshell.py