We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Missing resource breaks rendering viewlet.resourceregistries.js
if there's a typo or a missing JS resource defined in the resource registries, the `viewlet.resourceregistries.js` gives a traceback and all JS resources are missing.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `Products/CMFPlone/resources/utils.py`
Content:
```
1 from Acquisition import aq_base
2 from Acquisition import aq_inner
3 from Acquisition import aq_parent
4 from plone.base.interfaces.resources import OVERRIDE_RESOURCE_DIRECTORY_NAME
5 from plone.resource.file import FilesystemFile
6 from plone.resource.interfaces import IResourceDirectory
7 from Products.CMFCore.Expression import createExprContext
8 from Products.CMFCore.utils import getToolByName
9 from zExceptions import NotFound
10 from zope.component import queryUtility
11 
12 import logging
13 
14 
15 PRODUCTION_RESOURCE_DIRECTORY = "production"
16 logger = logging.getLogger(__name__)
17 
18 
19 def get_production_resource_directory():
20     persistent_directory = queryUtility(IResourceDirectory, name="persistent")
21     if persistent_directory is None:
22         return ""
23     container = persistent_directory[OVERRIDE_RESOURCE_DIRECTORY_NAME]
24     try:
25         production_folder = container[PRODUCTION_RESOURCE_DIRECTORY]
26     except NotFound:
27         return "%s/++unique++1" % PRODUCTION_RESOURCE_DIRECTORY
28     if "timestamp.txt" not in production_folder:
29         return "%s/++unique++1" % PRODUCTION_RESOURCE_DIRECTORY
30     timestamp = production_folder.readFile("timestamp.txt")
31     if isinstance(timestamp, bytes):
32         timestamp = timestamp.decode()
33     return "{}/++unique++{}".format(PRODUCTION_RESOURCE_DIRECTORY, timestamp)
34 
35 
36 def get_resource(context, path):
37     if path.startswith("++plone++"):
38         # ++plone++ resources can be customized, we return their override
39         # value if any
40         overrides = get_override_directory(context)
41         filepath = path[9:]
42         if overrides.isFile(filepath):
43             return overrides.readFile(filepath)
44 
45     if "?" in path:
46         # Example from plone.session:
47         # "acl_users/session/refresh?session_refresh=true&type=css&minutes=5"
48         # Traversing will not work then.  In this example we could split on "?"
49         # and traverse to the first part, acl_users/session/refresh, but this
50         # gives a function, and this fails when we call it below, missing a
51         # REQUEST argument
52         return
53     try:
54         resource = context.unrestrictedTraverse(path)
55     except (NotFound, AttributeError):
56         logger.warning(
57             f"Could not find resource {path}. You may have to create it first."
58         )  # noqa
59         return
60 
61     if isinstance(resource, FilesystemFile):
62         (directory, sep, filename) = path.rpartition("/")
63         return context.unrestrictedTraverse(directory).readFile(filename)
64 
65     # calling the resource may modify the header, i.e. the content-type.
66     # we do not want this, so keep the original header intact.
67     response_before = context.REQUEST.response
68     context.REQUEST.response = response_before.__class__()
69     if hasattr(aq_base(resource), "GET"):
70         # for FileResource
71         result = resource.GET()
72     else:
73         # any BrowserView
74         result = resource()
75     context.REQUEST.response = response_before
76     return result
77 
78 
79 def get_override_directory(context):
80     persistent_directory = queryUtility(IResourceDirectory, name="persistent")
81     if persistent_directory is None:
82         return
83     if OVERRIDE_RESOURCE_DIRECTORY_NAME not in persistent_directory:
84         persistent_directory.makeDirectory(OVERRIDE_RESOURCE_DIRECTORY_NAME)
85     return persistent_directory[OVERRIDE_RESOURCE_DIRECTORY_NAME]
86 
87 
88 def evaluateExpression(expression, context):
89     """Evaluate an object's TALES condition to see if it should be
90     displayed."""
91     try:
92         if expression.text and context is not None:
93             portal = getToolByName(context, "portal_url").getPortalObject()
94 
95             # Find folder (code courtesy of CMFCore.ActionsTool)
96             if context is None or not hasattr(context, "aq_base"):
97                 folder = portal
98             else:
99                 folder = context
100                 # Search up the containment hierarchy until we find an
101                 # object that claims it's PrincipiaFolderish.
102                 while folder is not None:
103                     if getattr(aq_base(folder), "isPrincipiaFolderish", 0):
104                         # found it.
105                         break
106                     else:
107                         folder = aq_parent(aq_inner(folder))
108 
109             __traceback_info__ = (folder, portal, context, expression)
110             ec = createExprContext(folder, portal, context)
111             # add 'context' as an alias for 'object'
112             ec.setGlobal("context", context)
113             return expression(ec)
114         return True
115     except AttributeError:
116         return True
117
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/Products/CMFPlone/resources/utils.py b/Products/CMFPlone/resources/utils.py
--- a/Products/CMFPlone/resources/utils.py
+++ b/Products/CMFPlone/resources/utils.py
@@ -52,7 +52,7 @@
         return
     try:
         resource = context.unrestrictedTraverse(path)
-    except (NotFound, AttributeError):
+    except (NotFound, AttributeError, KeyError):
         logger.warning(
             f"Could not find resource {path}. You may have to create it first."
         )  # noqa

{"golden_diff": "diff --git a/Products/CMFPlone/resources/utils.py b/Products/CMFPlone/resources/utils.py\n--- a/Products/CMFPlone/resources/utils.py\n+++ b/Products/CMFPlone/resources/utils.py\n@@ -52,7 +52,7 @@\n         return\n     try:\n         resource = context.unrestrictedTraverse(path)\n-    except (NotFound, AttributeError):\n+    except (NotFound, AttributeError, KeyError):\n         logger.warning(\n             f\"Could not find resource {path}. You may have to create it first.\"\n         )  # noqa\n", "issue": "Missing resource breaks rendering viewlet.resourceregistries.js\nif there's a typo or a missing JS resource defined in the resource registries, the `viewlet.resourceregistries.js` gives a traceback and all JS resources are missing.\n", "before_files": [{"content": "from Acquisition import aq_base\nfrom Acquisition import aq_inner\nfrom Acquisition import aq_parent\nfrom plone.base.interfaces.resources import OVERRIDE_RESOURCE_DIRECTORY_NAME\nfrom plone.resource.file import FilesystemFile\nfrom plone.resource.interfaces import IResourceDirectory\nfrom Products.CMFCore.Expression import createExprContext\nfrom Products.CMFCore.utils import getToolByName\nfrom zExceptions import NotFound\nfrom zope.component import queryUtility\n\nimport logging\n\n\nPRODUCTION_RESOURCE_DIRECTORY = \"production\"\nlogger = logging.getLogger(__name__)\n\n\ndef get_production_resource_directory():\n    persistent_directory = queryUtility(IResourceDirectory, name=\"persistent\")\n    if persistent_directory is None:\n        return \"\"\n    container = persistent_directory[OVERRIDE_RESOURCE_DIRECTORY_NAME]\n    try:\n        production_folder = container[PRODUCTION_RESOURCE_DIRECTORY]\n    except NotFound:\n        return \"%s/++unique++1\" % PRODUCTION_RESOURCE_DIRECTORY\n    if \"timestamp.txt\" not in production_folder:\n        return \"%s/++unique++1\" % PRODUCTION_RESOURCE_DIRECTORY\n    timestamp = production_folder.readFile(\"timestamp.txt\")\n    if isinstance(timestamp, bytes):\n        timestamp = timestamp.decode()\n    return \"{}/++unique++{}\".format(PRODUCTION_RESOURCE_DIRECTORY, timestamp)\n\n\ndef get_resource(context, path):\n    if path.startswith(\"++plone++\"):\n        # ++plone++ resources can be customized, we return their override\n        # value if any\n        overrides = get_override_directory(context)\n        filepath = path[9:]\n        if overrides.isFile(filepath):\n            return overrides.readFile(filepath)\n\n    if \"?\" in path:\n        # Example from plone.session:\n        # \"acl_users/session/refresh?session_refresh=true&type=css&minutes=5\"\n        # Traversing will not work then.  In this example we could split on \"?\"\n        # and traverse to the first part, acl_users/session/refresh, but this\n        # gives a function, and this fails when we call it below, missing a\n        # REQUEST argument\n        return\n    try:\n        resource = context.unrestrictedTraverse(path)\n    except (NotFound, AttributeError):\n        logger.warning(\n            f\"Could not find resource {path}. You may have to create it first.\"\n        )  # noqa\n        return\n\n    if isinstance(resource, FilesystemFile):\n        (directory, sep, filename) = path.rpartition(\"/\")\n        return context.unrestrictedTraverse(directory).readFile(filename)\n\n    # calling the resource may modify the header, i.e. the content-type.\n    # we do not want this, so keep the original header intact.\n    response_before = context.REQUEST.response\n    context.REQUEST.response = response_before.__class__()\n    if hasattr(aq_base(resource), \"GET\"):\n        # for FileResource\n        result = resource.GET()\n    else:\n        # any BrowserView\n        result = resource()\n    context.REQUEST.response = response_before\n    return result\n\n\ndef get_override_directory(context):\n    persistent_directory = queryUtility(IResourceDirectory, name=\"persistent\")\n    if persistent_directory is None:\n        return\n    if OVERRIDE_RESOURCE_DIRECTORY_NAME not in persistent_directory:\n        persistent_directory.makeDirectory(OVERRIDE_RESOURCE_DIRECTORY_NAME)\n    return persistent_directory[OVERRIDE_RESOURCE_DIRECTORY_NAME]\n\n\ndef evaluateExpression(expression, context):\n    \"\"\"Evaluate an object's TALES condition to see if it should be\n    displayed.\"\"\"\n    try:\n        if expression.text and context is not None:\n            portal = getToolByName(context, \"portal_url\").getPortalObject()\n\n            # Find folder (code courtesy of CMFCore.ActionsTool)\n            if context is None or not hasattr(context, \"aq_base\"):\n                folder = portal\n            else:\n                folder = context\n                # Search up the containment hierarchy until we find an\n                # object that claims it's PrincipiaFolderish.\n                while folder is not None:\n                    if getattr(aq_base(folder), \"isPrincipiaFolderish\", 0):\n                        # found it.\n                        break\n                    else:\n                        folder = aq_parent(aq_inner(folder))\n\n            __traceback_info__ = (folder, portal, context, expression)\n            ec = createExprContext(folder, portal, context)\n            # add 'context' as an alias for 'object'\n            ec.setGlobal(\"context\", context)\n            return expression(ec)\n        return True\n    except AttributeError:\n        return True\n", "path": "Products/CMFPlone/resources/utils.py"}], "after_files": [{"content": "from Acquisition import aq_base\nfrom Acquisition import aq_inner\nfrom Acquisition import aq_parent\nfrom plone.base.interfaces.resources import OVERRIDE_RESOURCE_DIRECTORY_NAME\nfrom plone.resource.file import FilesystemFile\nfrom plone.resource.interfaces import IResourceDirectory\nfrom Products.CMFCore.Expression import createExprContext\nfrom Products.CMFCore.utils import getToolByName\nfrom zExceptions import NotFound\nfrom zope.component import queryUtility\n\nimport logging\n\n\nPRODUCTION_RESOURCE_DIRECTORY = \"production\"\nlogger = logging.getLogger(__name__)\n\n\ndef get_production_resource_directory():\n    persistent_directory = queryUtility(IResourceDirectory, name=\"persistent\")\n    if persistent_directory is None:\n        return \"\"\n    container = persistent_directory[OVERRIDE_RESOURCE_DIRECTORY_NAME]\n    try:\n        production_folder = container[PRODUCTION_RESOURCE_DIRECTORY]\n    except NotFound:\n        return \"%s/++unique++1\" % PRODUCTION_RESOURCE_DIRECTORY\n    if \"timestamp.txt\" not in production_folder:\n        return \"%s/++unique++1\" % PRODUCTION_RESOURCE_DIRECTORY\n    timestamp = production_folder.readFile(\"timestamp.txt\")\n    if isinstance(timestamp, bytes):\n        timestamp = timestamp.decode()\n    return \"{}/++unique++{}\".format(PRODUCTION_RESOURCE_DIRECTORY, timestamp)\n\n\ndef get_resource(context, path):\n    if path.startswith(\"++plone++\"):\n        # ++plone++ resources can be customized, we return their override\n        # value if any\n        overrides = get_override_directory(context)\n        filepath = path[9:]\n        if overrides.isFile(filepath):\n            return overrides.readFile(filepath)\n\n    if \"?\" in path:\n        # Example from plone.session:\n        # \"acl_users/session/refresh?session_refresh=true&type=css&minutes=5\"\n        # Traversing will not work then.  In this example we could split on \"?\"\n        # and traverse to the first part, acl_users/session/refresh, but this\n        # gives a function, and this fails when we call it below, missing a\n        # REQUEST argument\n        return\n    try:\n        resource = context.unrestrictedTraverse(path)\n    except (NotFound, AttributeError, KeyError):\n        logger.warning(\n            f\"Could not find resource {path}. You may have to create it first.\"\n        )  # noqa\n        return\n\n    if isinstance(resource, FilesystemFile):\n        (directory, sep, filename) = path.rpartition(\"/\")\n        return context.unrestrictedTraverse(directory).readFile(filename)\n\n    # calling the resource may modify the header, i.e. the content-type.\n    # we do not want this, so keep the original header intact.\n    response_before = context.REQUEST.response\n    context.REQUEST.response = response_before.__class__()\n    if hasattr(aq_base(resource), \"GET\"):\n        # for FileResource\n        result = resource.GET()\n    else:\n        # any BrowserView\n        result = resource()\n    context.REQUEST.response = response_before\n    return result\n\n\ndef get_override_directory(context):\n    persistent_directory = queryUtility(IResourceDirectory, name=\"persistent\")\n    if persistent_directory is None:\n        return\n    if OVERRIDE_RESOURCE_DIRECTORY_NAME not in persistent_directory:\n        persistent_directory.makeDirectory(OVERRIDE_RESOURCE_DIRECTORY_NAME)\n    return persistent_directory[OVERRIDE_RESOURCE_DIRECTORY_NAME]\n\n\ndef evaluateExpression(expression, context):\n    \"\"\"Evaluate an object's TALES condition to see if it should be\n    displayed.\"\"\"\n    try:\n        if expression.text and context is not None:\n            portal = getToolByName(context, \"portal_url\").getPortalObject()\n\n            # Find folder (code courtesy of CMFCore.ActionsTool)\n            if context is None or not hasattr(context, \"aq_base\"):\n                folder = portal\n            else:\n                folder = context\n                # Search up the containment hierarchy until we find an\n                # object that claims it's PrincipiaFolderish.\n                while folder is not None:\n                    if getattr(aq_base(folder), \"isPrincipiaFolderish\", 0):\n                        # found it.\n                        break\n                    else:\n                        folder = aq_parent(aq_inner(folder))\n\n            __traceback_info__ = (folder, portal, context, expression)\n            ec = createExprContext(folder, portal, context)\n            # add 'context' as an alias for 'object'\n            ec.setGlobal(\"context\", context)\n            return expression(ec)\n        return True\n    except AttributeError:\n        return True\n", "path": "Products/CMFPlone/resources/utils.py"}]}