# Buggy code
def upgrade(ver, session):
    if ver == 0:
        table = table_schema("input_cache_entry", session)
        table_add_column(table, "json", Unicode, session)
        # Make sure we get the new schema with the added column
        table = table_schema("input_cache_entry", session)
        for row in session.execute(select([table.c.id, table.c.entry])):
            try:
                p = pickle.loads(row["entry"])
                session.execute(
                    table.update()
                    .where(table.c.id == row["id"])
                    .values(json=json.dumps(p, encode_datetime=True))
                )
            except KeyError as e:
                logger.error(
                    "Unable error upgrading input_cache pickle object due to {}", str(e)
                )
        ver = 1
    if ver == 1:
        table = table_schema("input_cache_entry", session)
        for row in session.execute(select([table.c.id, table.c.json])):
            if not row["json"]:
                # Seems there could be invalid data somehow. See #2590
                continue
            data = json.loads(row["json"], decode_datetime=True)
            # If title looked like a date, make sure it's a string
            title = str(data.pop("title"))
            e = Entry(title=title, **data)
            session.execute(
                table.update()
                .where(table.c.id == row["id"])
                .values(json=serialization.dumps(e))
            )

        ver = 2
    return ver


# Traceback (KeyError)
2020-03-22 16:58:34.940 | DEBUG    | flexget.tray_icon:<module>:20 - Could not import pystray: libopenjp2.so.7: cannot open shared object file: No such file or directory
2020-03-22 16:58:38 INFO     manager                       Database upgrade is required. Attempting now.
2020-03-22 16:58:39 ERROR    schema                        Failed to upgrade database for plugin input_cache: 'title'
Traceback (most recent call last):
File "/home/pi/flexget/bin/flexget", line 8, in <module>
sys.exit(main())
|   |    -> <function main at 0xb66dea98>
|   -> <built-in function exit>
-> <module 'sys' (built-in)>
File "/home/pi/flexget/lib/python3.7/site-packages/flexget/__init__.py", line 41, in main
manager.start()
|       -> <function Manager.start at 0xb5293738>
-> <flexget.manager.Manager object at 0xb66df910>
File "/home/pi/flexget/lib/python3.7/site-packages/flexget/manager.py", line 375, in start
self.initialize()
|    -> <function Manager.initialize at 0xb528a270>
-> <flexget.manager.Manager object at 0xb66df910>
File "/home/pi/flexget/lib/python3.7/site-packages/flexget/manager.py", line 242, in initialize
fire_event('manager.upgrade', self)
|                             -> <flexget.manager.Manager object at 0xb66df910>
-> <function fire_event at 0xb57b2bb8>
File "/home/pi/flexget/lib/python3.7/site-packages/flexget/event.py", line 112, in fire_event
result = event(*args, **kwargs)
|      |       -> {}
|      -> (<flexget.manager.Manager object at 0xb66df910>,)
-> <Event(name=manager.upgrade,func=upgrade_wrapper,priority=128)>
File "/home/pi/flexget/lib/python3.7/site-packages/flexget/event.py", line 22, in __call__
return self.func(*args, **kwargs)
|    |     |       -> {}
|    |     -> (<flexget.manager.Manager object at 0xb66df910>,)
|    -> <function upgrade.<locals>.upgrade_decorator.<locals>.upgrade_wrapper at 0xb21e8cd8>
-> <Event(name=manager.upgrade,func=upgrade_wrapper,priority=128)>
File "/home/pi/flexget/lib/python3.7/site-packages/flexget/db_schema.py", line 154, in upgrade_wrapper
new_ver = upgrade_func(current_ver, session)
|            |            -> <sqlalchemy.orm.session.ContextSession object at 0xb0e70eb0>
|            -> 1
-> <function upgrade at 0xb21e8c48>
File "/home/pi/flexget/lib/python3.7/site-packages/flexget/utils/cached_input.py", line 49, in upgrade
title = str(data.pop('title'))
|    -> <method 'pop' of 'dict' objects>
-> {'serializer': 'Entry', 'version': 1, 'value': {'fields': {'original_url': 'https://trakt.tv/shows/true-detective', 'url': 'h...

KeyError: 'title'
Traceback (most recent call last):
File "/home/pi/flexget/lib/python3.7/site-packages/flexget/db_schema.py", line 154, in upgrade_wrapper
new_ver = upgrade_func(current_ver, session)
File "/home/pi/flexget/lib/python3.7/site-packages/flexget/utils/cached_input.py", line 49, in upgrade
title = str(data.pop('title'))
KeyError: 'title'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "/home/pi/flexget/bin/flexget", line 8, in <module>
sys.exit(main())
File "/home/pi/flexget/lib/python3.7/site-packages/flexget/__init__.py", line 41, in main
manager.start()
File "/home/pi/flexget/lib/python3.7/site-packages/flexget/manager.py", line 375, in start
self.initialize()
File "/home/pi/flexget/lib/python3.7/site-packages/flexget/manager.py", line 242, in initialize
fire_event('manager.upgrade', self)
File "/home/pi/flexget/lib/python3.7/site-packages/flexget/event.py", line 112, in fire_event
result = event(*args, **kwargs)
File "/home/pi/flexget/lib/python3.7/site-packages/flexget/event.py", line 22, in __call__
return self.func(*args, **kwargs)
File "/home/pi/flexget/lib/python3.7/site-packages/flexget/db_schema.py", line 165, in upgrade_wrapper
manager.shutdown(finish_queue=False)
File "/home/pi/flexget/lib/python3.7/site-packages/flexget/manager.py", line 1033, in shutdown
raise RuntimeError('Cannot shutdown manager that was never initialized.')
RuntimeError: Cannot shutdown manager that was never initialized.
(flexget) pi@pi4:~ $

# Fixed code
def upgrade(ver, session):
    if ver == 0:
        table = table_schema("input_cache_entry", session)
        table_add_column(table, "json", Unicode, session)
        # Make sure we get the new schema with the added column
        table = table_schema("input_cache_entry", session)
        for row in session.execute(select([table.c.id, table.c.entry])):
            try:
                p = pickle.loads(row["entry"])
                session.execute(
                    table.update()
                    .where(table.c.id == row["id"])
                    .values(json=json.dumps(p, encode_datetime=True))
                )
            except KeyError as e:
                logger.error(
                    "Unable error upgrading input_cache pickle object due to {}", str(e)
                )
        ver = 1
    if ver == 1:
        table = table_schema("input_cache_entry", session)
        for row in session.execute(select([table.c.id, table.c.json])):
            if not row["json"]:
                # Seems there could be invalid data somehow. See #2590
                continue
            data = json.loads(row["json"], decode_datetime=True)
            # If title looked like a date, make sure it's a string
            # Had a weird case of an entry without a title: https://github.com/Flexget/Flexget/issues/2636
            title = data.pop("title", None)
            entry = partial(Entry, **data)
            e = entry(title=str(title)) if title else entry()
            session.execute(
                table.update()
                .where(table.c.id == row["id"])
                .values(json=serialization.dumps(e))
            )

        ver = 2
    return ver