I'm making a Flask webapp and I'm using Flask-Socketio. For various reasons, I have a need to also use the websocket-client package. Everything is working as intended, except that when I tried running the app on a different computer on a different network, I get the following error:
"""
Traceback (most recent call last):
File "[Path to venv]\venv\lib\site-packages\flask\app.py", line 2449, in wsgi_app
response = self.handle_exception(e)
File "[Path to venv]\venv\lib\site-packages\flask\app.py", line 1866, in handle_exception
reraise(exc_type, exc_value, tb)
File "[Path to venv]\venv\lib\site-packages\flask\_compat.py", line 39, in reraise
raise value
File "[Path to venv]\venv\lib\site-packages\flask\app.py", line 2446, in wsgi_app
response = self.full_dispatch_request()
File "[Path to venv]\venv\lib\site-packages\flask\app.py", line 1951, in full_dispatch_request
rv = self.handle_user_exception(e)
File "[Path to venv]\venv\lib\site-packages\flask\app.py", line 1820, in handle_user_exception
reraise(exc_type, exc_value, tb)
File "[Path to venv]\venv\lib\site-packages\flask\_compat.py", line 39, in reraise
raise value
File "[Path to venv]\venv\lib\site-packages\flask\app.py", line 1949, in full_dispatch_request
rv = self.dispatch_request()
File "[Path to venv]\venv\lib\site-packages\flask\app.py", line 1935, in dispatch_request
return self.view_functions[rule.endpoint](**req.view_args)
File "[Path to app]\app\views.py", line 7, in index
sio.connect("http://localhost:80/", transports=['websocket', 'polling'])
File "[Path to venv]\venv\lib\site-packages\socketio\client.py", line 262, in connect
engineio_path=socketio_path)
File "[Path to venv]\venv\lib\site-packages\engineio\client.py", line 170, in connect
url, headers, engineio_path)
File "[Path to venv]\venv\lib\site-packages\engineio\client.py", line 346, in _connect_websocket
cookie=cookies)
File "[Path to venv]\venv\lib\site-packages\websocket\_core.py", line 514, in create_connection
websock.connect(url, **options)
File "[Path to venv]\venv\lib\site-packages\websocket\_core.py", line 223, in connect
options.pop('socket', None))
File "[Path to venv]\venv\lib\site-packages\websocket\_http.py", line 120, in connect
sock = _open_socket(addrinfo_list, options.sockopt, options.timeout)
File "[Path to venv]\venv\lib\site-packages\websocket\_http.py", line 189, in _open_socket
raise error
File "[Path to venv]\venv\lib\site-packages\websocket\_http.py", line 172, in _open_socket
sock.connect(address)
OSError: [WinError 10057] A request to send or receive data was disallowed because
the socket is not connected and (when sending on a datagram socket using a sendto call)
no address was supplied
"""
I've boiled down my code as much as possible to the following, which still works on my computer, but gives the same error on the other:
|start.py
|app
|__init__.py
|views.py
|templates
|index.html
# __init__.py
from flask import Flask
from flask_socketio import SocketIO
from gevent import monkey
monkey.patch_all()
APP = Flask(__name__)
SOCKETIO = SocketIO(APP, engineio_logger=True, logger=True)
from . import views
# views.py
from app import APP
from socketio import Client
from flask import render_template
#APP.route('/', methods=['GET', 'POST'])
def index():
sio = Client()
sio.connect("http://localhost:80", transports=['websocket', 'polling']) # Error being caused here
return render_template('index.html')
# start.py
from app import APP, SOCKETIO
if __name__ == "__main__":
SOCKETIO.run(APP, debug=True, port=80, host='0.0.0.0')
index.html is just a basic 'Hello World' html page.
What kind of stuff might give me this error on one computer/network an not another, especially just running it on localhost:80? I really don't know what to try here.
EDIT: Added traceback data to error
EDIT 2: In my actual code, the websocket.Client is being run inside a Celery task. I didn't include it here because the error is reproduceable without going into that much complexity.
The problem is when you try to run -(Flask-webapp, websocket-client)- both of them simultaneously, only one of them will be running.
Update:
Here are some things to be noted:
If you changing machine, make sure system-softwares are already up-to-date.
Check your system is not behind firewall but when you're running Flask webapp and websocket-client on the same machine then there is not need of this step.
Try to restart your machine after update your OS.
Use multiprocessing instead of Threads as they won't work here because the famous Python-Global-Interpreter or GIL. According to which Only one thread can be in a state of execution at any point in time.
The impact of the GIL isn’t visible to developers who execute
single-threaded programs, but it can be a - Performance-bottleneck - in
CPU-bound and multi-threaded code.
Then Check: How to run flask on Port:80. For development purposes Port:5000 is mostly recommended.
In order to perform "Error Handling" visit the flask-socketio documentation, there is nice tips to to deal with exceptions.
You can go as follow:
#socketio.on_error_default # handles all namespaces without an explicit error handler
def default_error_handler(e):
pass
And finally, to handle socket.timeout, you may also use this following code to handle the final error: socket timed out:
try:
socketio.run(app,...
except socket.error as socketerror:
print("Error: ", socketerror)
It would be an better approach to use postman.For learning and testing purpose, try to use POSTMAN which is a quick and easy platform for sending REST, SOAP, and GraphQL requests directly within Postman. Visit reference: getting-started-postman.
Here is an example program:
import multiprocessing
# Assume for flask-app
def start_flask_app:
app.run()
# Assume for websocket-client-app
# Assume basic events you will handle in your client e.g. on_message, on_error, on_close
def start_ws:
ws = websocket.WebSocketApp(WS_URI, on_message= on_message,
on_error = on_error,
on_close = on_close)
ws.on_open = on_open
ws.run_forever()
# use of sub-processes instead of threads.
p_flask = multiprocessing.Process(target=start_flask_app)
p_ws = multiprocessing.Process(target=start_ws)
p_ws.start()
p_flask.start()
p_ws.join()
p_flask.join()
Related
Hello everyone I will explain my problem as clearly as possible. I have a Flask application and I want to retrieve the uid from the url settings and then check if the user exists in my Firebase Cloud Firestore using an await.
But I have an error, when my application has to process the same request several times in a short time, I have this error:
127.0.0.1 - - [27/Sep/2022 22:37:04] "GET /firestore/petale?uid=user123456789 HTTP/1.1" 200 -
[2022-09-27 22:37:08,883] ERROR in app: Exception on /firestore/petale?uid=user123456789 [GET]
Traceback (most recent call last):
File "C:\Users\HP\IdeaProjects\flaskapp\lib\site-packages\flask\app.py", line 2525, in wsgi_app
response = self.full_dispatch_request()
File "C:\Users\HP\IdeaProjects\flaskapp\lib\site-packages\flask\app.py", line 1822, in full_dispatch_request
rv = self.handle_user_exception(e)
File "C:\Users\HP\IdeaProjects\flaskapp\lib\site-packages\flask\app.py", line 1820, in full_dispatch_request
rv = self.dispatch_request()
File "C:\Users\HP\IdeaProjects\flaskapp\lib\site-packages\flask\app.py", line 1796, in dispatch_request
return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args)
File "C:\Users\HP\PycharmProjects\flaskapp\routes\petale.py", line 14, in index
loop = asyncio.run(checkUid(uid))
File "C:\Users\HP\AppData\Local\Programs\Python\Python310\lib\asyncio\runners.py", line 44, in run
return loop.run_until_complete(main)
File "C:\Users\HP\AppData\Local\Programs\Python\Python310\lib\asyncio\base_events.py", line 646, in run_until_complete
return future.result()
File "C:\Users\HP\PycharmProjects\flaskapp\routes\petale.py", line 21, in checkUid
uid_doc = await document.get()
File "C:\Users\HP\IdeaProjects\flaskapp\lib\site-packages\google\cloud\firestore_v1\async_document.py", line 367, in get
response_iter = await self._client._firestore_api.batch_get_documents(
File "C:\Users\HP\IdeaProjects\flaskapp\lib\site-packages\google\api_core\grpc_helpers_async.py", line 168, in error_remapped_callable
call = callable_(*args, **kwargs)
File "C:\Users\HP\IdeaProjects\flaskapp\lib\site-packages\grpc\aio\_channel.py", line 168, in __call__
call = UnaryStreamCall(request, deadline, metadata, credentials,
File "C:\Users\HP\IdeaProjects\flaskapp\lib\site-packages\grpc\aio\_call.py", line 555, in __init__
self._send_unary_request_task = loop.create_task(
File "C:\Users\HP\AppData\Local\Programs\Python\Python310\lib\asyncio\base_events.py", line 436, in create_task
self._check_closed()
File "C:\Users\HP\AppData\Local\Programs\Python\Python310\lib\asyncio\base_events.py", line 515, in _check_closed
raise RuntimeError('Event loop is closed')
RuntimeError: Event loop is closed
127.0.0.1 - - [27/Sep/2022 22:37:08] "GET /firestore/petale?uid=user123456789 HTTP/1.1" 500 -
The highlighted error is: RuntimeError: Event loop is closed
You should know that I'm quite new to all the async/await methods, I come from Android with Java and it's not common for me. After several tests I could see that it comes from the line that retrieves the user's document with the await uid_doc = await document.get()
Searching on the internet I could see that people have this problem when they use the asyncio package, but I had not used it in my code. I decided to use it but I still have the same error and I don't know how to fix the problem. I don't really understand how to use asyncio.
import asyncio
from flask import Blueprint, request
from firebase_admin import firestore_async
petale = Blueprint("petale", __name__)
collection = firestore_async.client().collection('xxxx')
#petale.route("/petale", methods=['GET'])
def index():
uid = request.args.get('uid')
asyncio.set_event_loop(asyncio.new_event_loop())
loop = asyncio.run(checkUid(uid))
return loop
async def checkUid(uid):
document = collection.document(uid)
uid_doc = await document.get()
if uid_doc.exists:
return "Exists"
else:
return "Error"
I tried aioflask but there are many problems with it, I tried installing pip install flask[async] but it doesn't work either.
I'm a bit desperate, can you help me?
Thanks a lot!
Here is my script
"""
Concerto library
"""
import win32com.client
def concerto_authenticate(encrypted_request, expiry, mac):
"""
Authenticate request
"""
concerto_request = win32com.client.Dispatch(
"Concerto4xSecurity.ValidatedRequest")
secret_key = "XXX"
concerto_request.SetSecretKey(secret_key)
concerto_request.setEncryptedRequest(encrypted_request)
concerto_request.SetExpiry(expiry)
concerto_request.SetMAC(mac)
concerto_request.Validate()
return concerto_request
I call it from another page as so:
concerto_request = concerto.concerto_authenticate(encrypted_request, expiry, mac)
This works fine in my DEV environment. I am using Windows 2016 and IIS. It's using the inbuilt server that comes with Flask. Nothing fancy.
I moved all my files to PROD. Both DEV and PROD sit on the same server so have access to the exact same libraries. The only difference is that PROD uses Waitress.
No, when I run my code in PROD I get the following. This does not happen on the DEV URL, just the PROD one. The only difference being PROD uses Waitress and DEV does not.
Any suggestions?
Traceback (most recent call last):
File "C:\Python310\lib\site-packages\flask\app.py", line 2077, in wsgi_app
response = self.full_dispatch_request()
File "C:\Python310\lib\site-packages\flask\app.py", line 1525, in full_dispatch_request
rv = self.handle_user_exception(e)
File "C:\Python310\lib\site-packages\flask\app.py", line 1523, in full_dispatch_request
rv = self.dispatch_request()
File "C:\Python310\lib\site-packages\flask\app.py", line 1509, in dispatch_request
return self.ensure_sync(self.view_functions[rule.endpoint])(**req.view_args)
File "E:\Apps\prod\digital\gp_clinicals\gp_clinicals.py", line 43, in gp_clinicals
concerto_request = concerto.concerto_authenticate(encrypted_request, expiry, mac)
File "E:\Apps\prod\digital\concerto.py", line 11, in concerto_authenticate
concerto_request = win32com.client.Dispatch(
File "C:\Python310\lib\site-packages\win32com\client\__init__.py", line 117, in Dispatch
dispatch, userName = dynamic._GetGoodDispatchAndUserName(dispatch, userName, clsctx)
File "C:\Python310\lib\site-packages\win32com\client\dynamic.py", line 106, in _GetGoodDispatchAndUserName
return (_GetGoodDispatch(IDispatch, clsctx), userName)
File "C:\Python310\lib\site-packages\win32com\client\dynamic.py", line 88, in _GetGoodDispatch
IDispatch = pythoncom.CoCreateInstance(
pywintypes.com_error: (-2147221008, 'CoInitialize has not been called.', None, None)
2022-08-01 13:15:12,592 - ERROR - __init__.py - handle_error_500 - 88 - 500 Internal Server Error: The server encountered an internal error and was unable to complete your request. Either the server is overloaded or there is an error in the application.
prod wsgi.py
"""
Application entry point
"""
from digital import init_app
from waitress import serve
app = init_app()
if __name__ == "__main__":
serve(app, host="internal.prod", url_scheme='https')
dev wsgi.py
"""
Application entry point
"""
from digital import init_app
app = init_app()
if __name__ == "__main__":
app.run(host="internal.dev",threaded=True)
I am using Google AppEngine (GAE) Flexible environment with a custom runtime (python2.7). I am using custom so I can just manage a Dockerfile and have easy parity between my laptop and when deployed in GAE.
I have a python 2.7 Flask app that is doing a query against DataStore. I get the following (when starting python main.py in my local docker):
root#24dcf9b8712d:/home/vmagent/app# curl localhost:5000/things
'/home/vmagent/app/clientid-searchapp.json'
[2018-09-04 14:54:19,969] ERROR in app: Exception on /things [GET]
Traceback (most recent call last):
File "/env/local/lib/python2.7/site-packages/flask/app.py", line 2292, in wsgi_app
response = self.full_dispatch_request()
File "/env/local/lib/python2.7/site-packages/flask/app.py", line 1815, in full_dispatch_request
rv = self.handle_user_exception(e)
File "/env/local/lib/python2.7/site-packages/flask/app.py", line 1718, in handle_user_exception
reraise(exc_type, exc_value, tb)
File "/env/local/lib/python2.7/site-packages/flask/app.py", line 1813, in full_dispatch_request
rv = self.dispatch_request()
File "/env/local/lib/python2.7/site-packages/flask/app.py", line 1799, in dispatch_request
return self.view_functions[rule.endpoint](**req.view_args)
File "main.py", line 55, in products
for rec in query.fetch(limit=100):
File "/env/lib/python2.7/site-packages/google/api_core/page_iterator.py", line 199, in _items_iter
for page in self._page_iter(increment=False):
File "/env/lib/python2.7/site-packages/google/api_core/page_iterator.py", line 230, in _page_iter
page = self._next_page()
File "/env/local/lib/python2.7/site-packages/google/cloud/datastore/query.py", line 517, in _next_page
query=query_pb,
File "/env/local/lib/python2.7/site-packages/google/cloud/datastore_v1/gapic/datastore_client.py", line 294, in run_query
request, retry=retry, timeout=timeout, metadata=metadata)
File "/env/lib/python2.7/site-packages/google/api_core/gapic_v1/method.py", line 139, in __call__
return wrapped_func(*args, **kwargs)
File "/env/lib/python2.7/site-packages/google/api_core/retry.py", line 260, in retry_wrapped_func
on_error=on_error,
File "/env/lib/python2.7/site-packages/google/api_core/retry.py", line 177, in retry_target
return target()
File "/env/lib/python2.7/site-packages/google/api_core/timeout.py", line 206, in func_with_timeout
return func(*args, **kwargs)
File "/env/lib/python2.7/site-packages/google/api_core/grpc_helpers.py", line 56, in error_remapped_callable
six.raise_from(exceptions.from_grpc_error(exc), exc)
File "/env/local/lib/python2.7/site-packages/six.py", line 737, in raise_from
raise value
PermissionDenied: 403 Missing or insufficient permissions.
127.0.0.1 - - [04/Sep/2018 14:54:19] "GET /things HTTP/1.1" 500 -
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<title>500 Internal Server Error</title>
<h1>Internal Server Error</h1>
<p>The server encountered an internal error and was unable to complete your request. Either the server is overloaded or there is an error in the application.</p>
Snippets from main.py
app = Flask(__name__)
ds = datastore.Client()
<snip>
#app.route("/things")
def things():
global ds
pprint(os.environ['GOOGLE_APPLICATION_CREDENTIALS'])
query = ds.query(kind='Things', order=('thing_name',))
results = list()
for rec in query.fetch(limit=100):
results.append(rec)
return jsonify(results)
Output of gcloud auth list:
root#24dcf9b8712d:/home/vmagent/app# gcloud auth list
Credentialed Accounts
ACTIVE ACCOUNT
* <myapp>#<project-name>.iam.gserviceaccount.com
This is the configured service account. I have over-privileged it with excessive Role membership; I'm pretty certain the service account isn't lacking in permissions. In fact, it has 'DataStore Owner'
In main.py I am outputting:
pprint(os.environ['GOOGLE_APPLICATION_CREDENTIALS'])
And this outputs the path to my client-<myapp>.json file for the service account. It is the same file supplied in the Dockerfile as:
RUN gcloud auth activate-service-account --key-file=clientid-<myapp>.json --project <project-name> --quiet
I get the same results when running the Flask app in my local Docker environment and when I deploy to GAE Flexible. The Flask app has other endpoints that work as they don't call any other services. Only /things uses an API to call DataStore and it receives the above error.
I've been through all the docs. I'm sure it's something basic and obvious but afaict, everything looks right.
UPDATE:
I've tried creating the DataStore client with an explicit pass of project name with no change in result. Also, I've run this command from within the Docker container and this seems like unusual output to me but I don't know that it's incorrect for a Service Account.
root#e02b74cd269d:/home/vmagent/app# gcloud projects list
API [cloudresourcemanager.googleapis.com] not enabled on project
[<project id>]. Would you like to enable and retry (this will take a
few minutes)? (y/N)? y
When I respond w/ Y,:
ERROR: (gcloud.projects.list) PERMISSION_DENIED: Not allowed to get project settings for project <project id>
Output of gcloud config list:
root#d18c83cae166:/home/vmagent/app# gcloud config list
[core]
account = <myapp>#<myproject>.iam.gserviceaccount.com
disable_usage_reporting = False
project = <myproject>
Your active configuration is: [default]
I am trying to access MeisterTask's API with Python and Flask, and no matter what I do, I seem to always get a 302 code in return from the API, although I can get an access token (or so I think). Here is the code I have so far (I tried reducing it, this is the smallest snippet I could get that replicates the error):
from flask import Flask, redirect, url_for, session, request, jsonify
from flask_oauthlib.client import OAuth
app = Flask(__name__)
app.debug = True
app.secret_key = "development"
oauth = OAuth(app)
meistertask = oauth.remote_app(
'meistertask',
consumer_key= "XXXXXX",
consumer_secret= "XXXXXX",
request_token_params={"scope" : "meistertask"},
base_url='https://www.meistertask.com/api',
request_token_url=None,
access_token_method='GET',
access_token_url='https://www.mindmeister.com/login/oauth2/token',
authorize_url='https://www.mindmeister.com/oauth2/authorize'
)
#app.route('/')
def index():
if 'meistertask_token' in session:
me = meistertask.get('user')
return jsonify(me.data)
return redirect(url_for('login'))
#app.route('/login')
def login():
return meistertask.authorize(callback=url_for('authorized', _external=True))
#app.route('/logout')
def logout():
session.pop('meistertask_token', None)
return redirect(url_for('index'))
#app.route('/login/authorized')
def authorized():
resp = meistertask.authorized_response()
print(resp.get('code'))
if resp is None or resp.get('code') is None:
return 'Access denied: reason=%s error=%s resp=%s' % (
request.args['error'],
request.args['error_description'],
resp
)
session['meistertask_token'] = (resp['code'], '')
return "Hello"
#meistertask.tokengetter
def get_meistertask_oauth_token():
return session.get('meistertask_token')
if __name__ == "__main__":
app.run()
And here is the traceback:
flask_oauthlib.client.OAuthException: Invalid response from meistertask
Traceback (most recent call last):
File "~\AppData\Local\Programs\Python\Python37-32\lib\site-packages\flask\app.py", line 2309, in __call__ return self.wsgi_app(environ, start_response)
File "~\AppData\Local\Programs\Python\Python37-32\lib\site-packages\flask\app.py", line 2295, in wsgi_app response = self.handle_exception(e)
File "~\AppData\Local\Programs\Python\Python37-32\lib\site-packages\flask\app.py", line 1741, in handle_exception reraise(exc_type, exc_value, tb)
File "~\AppData\Local\Programs\Python\Python37-32\lib\site-packages\flask\_compat.py", line 35, in reraise raise value
File "~\AppData\Local\Programs\Python\Python37-32\lib\site-packages\flask\app.py", line 2292, in wsgi_app response = self.full_dispatch_request()
File "~\AppData\Local\Programs\Python\Python37-32\lib\site-packages\flask\app.py", line 1815, in full_dispatch_request rv = self.handle_user_exception(e)
File "~\AppData\Local\Programs\Python\Python37-32\lib\site-packages\flask\app.py", line 1718, in handle_user_exception reraise(exc_type, exc_value, tb)
File "~\AppData\Local\Programs\Python\Python37-32\lib\site-packages\flask\_compat.py", line 35, in reraise raise value
File "~\AppData\Local\Programs\Python\Python37-32\lib\site-packages\flask\app.py", line 1813, in full_dispatch_request rv = self.dispatch_request()
File "~\AppData\Local\Programs\Python\Python37-32\lib\site-packages\flask\app.py", line 1799, in dispatch_request return self.view_functions[rule.endpoint](**req.view_args)
File "~\Documents\MeisterTaskServer\hello.py", line 49, in authorized resp = meistertask.authorized_response()
File "~\AppData\Local\Programs\Python\Python37-32\lib\site-packages\flask_oauthlib\client.py", line 707, in authorized_response data = self.handle_oauth2_response(args)
File "~\AppData\Local\Programs\Python\Python37-32\lib\site-packages\flask_oauthlib\client.py", line 692, in handle_oauth2_response
Things I have tried
Tried to modify the method to get the access token from GET to POST. The API clearly states that I should use GET, yet every other example I have seen on flask_oauthlib's GitHub uses POST (the examples are 3 years old, but some still work, namely the GitHub one). Either give the same result.
Tried doing it barebones, without any library. The resulting code was thrice as long and also had more problems.
Used Django instead of Flask. Never even managed to get the hello world example going, it was too much work, and also I have discovered the library flask_oauthlib.
Things worth mentioning
I derived this code from this here GitHub example
There is also code there I omitted in order to keep the snippet short, that establishes that the server should use SSL (as per the request from the API that the redirect_uri should use HTTPS)
The app manages to redirect me over at MeisterTask and asks for my permission. Once I grant it, it redirects to "https://127.0.0.1:5000/login/authorized?code=some_token" where I get the traceback. If I look with Chrome's debugging tools to the requests made and what I receive, I see that I get an 302 from the API, but I also get an access token.
I run Windows 10 with Python 3.7.0
So what's the deal? What's the next step here? I've run out of things to try. Thank you for taking the time to solve this!
I'm aware that once I have everything up and running on a production server, nginx or apache are supposed to be serving static assets instead of Flask. In the interest of getting started quickly though, I'm running into an issue with Flask and requests to files in subdirectories of static.
A request for /static/test.css returns correctly, but a request for /static/test/test.css returns a 500 and throws this exception:
Traceback (most recent call last):
File "/home/tim/shadowcraft-ui-python/venv/lib/python3.5/site-packages/flask/app.py", line 1991, in wsgi_app
response = self.make_response(self.handle_exception(e))
File "/home/tim/shadowcraft-ui-python/venv/lib/python3.5/site-packages/flask/app.py", line 1567, in handle_exception
reraise(exc_type, exc_value, tb)
File "/home/tim/shadowcraft-ui-python/venv/lib/python3.5/site-packages/flask/_compat.py", line 33, in reraise
raise value
File "/home/tim/shadowcraft-ui-python/venv/lib/python3.5/site-packages/flask/app.py", line 1988, in wsgi_app
response = self.full_dispatch_request()
File "/home/tim/shadowcraft-ui-python/venv/lib/python3.5/site-packages/flask/app.py", line 1642, in full_dispatch_request
response = self.make_response(rv)
File "/home/tim/shadowcraft-ui-python/venv/lib/python3.5/site-packages/flask/app.py", line 1731, in make_response
raise ValueError('View function did not return a response')
ValueError: View function did not return a response
A bit of searching on that error returns mostly simple cases where someone forgot a return in a request handler, but nothing for when making direct requests for assets. It also does the same thing if trying to use url_for in a template to request the file from the subdirectory.
This ended up being an error in my code. I have a route handler that takes three parts as arguments, and since that handler isn't implemented yet, it caused Flask to throw the exception above. I ended up implementing the solution from Does Flask support regular expressions in its URL routing? for that handler since I know the first part is always one of a few different values, and the static handler can run as normal.