AssertionError: Request global variable is not set

1,306 views
Skip to first unread message

Jakob Holmelund

unread,
Jun 8, 2012, 5:42:20 AM6/8/12
to web...@googlegroups.com
Hi guys, i really want to get to the bottom of this. 

AssertionError: Request global variable is not set


I get this error the first time call

user = self.auth.get_user_by_session()

after an instance is started. So that means that any user who gets a new instance will run into an error which is not acceptable.

I have found some earlier threads where this error was produces by importing an app inside a function. I dont think that its the same thing going on here, so if someone has fixed this, please help.

Im using Python 2.7 and ndb, so i wrap my app with ndb.toplevel like:

app = ndb.toplevel(webapp2.WSGIApplication(routes.URLS, debug=config.DEBUG, config=config.CONFIG))

Here is a stack trace of the error

Request global variable is not set.
Traceback (most recent call last):
 
File "/base/python27_runtime/python27_lib/versions/third_party/webapp2-2.5.1/webapp2.py", line 1536, in __call__
    rv
= self.handle_exception(request, response, e)
 
File "/base/python27_runtime/python27_lib/versions/third_party/webapp2-2.5.1/webapp2.py", line 1530, in __call__
    rv
= self.router.dispatch(request, response)
 
File "/base/python27_runtime/python27_lib/versions/third_party/webapp2-2.5.1/webapp2.py", line 1278, in default_dispatcher
   
return route.handler_adapter(request, response)
 
File "/base/python27_runtime/python27_lib/versions/third_party/webapp2-2.5.1/webapp2.py", line 1102, in __call__
   
return handler.dispatch()
 
File "/base/data/home/apps/s~kobstadendev/1.359392875892326983/main.py", line 81, in dispatch
    webapp2
.RequestHandler.dispatch(self)
 
File "/base/python27_runtime/python27_lib/versions/third_party/webapp2-2.5.1/webapp2.py", line 572, in dispatch
   
return self.handle_exception(e, self.app.debug)
 
File "/base/python27_runtime/python27_lib/versions/third_party/webapp2-2.5.1/webapp2.py", line 570, in dispatch
   
return method(*args, **kwargs)
 
File "/base/python27_runtime/python27_lib/versions/1/google/appengine/ext/ndb/tasklets.py", line 1009, in synctasklet_wrapper
   
return taskletfunc(*args, **kwds).get_result()
 
File "/base/python27_runtime/python27_lib/versions/1/google/appengine/ext/ndb/tasklets.py", line 322, in get_result
   
self.check_success()
 
File "/base/python27_runtime/python27_lib/versions/1/google/appengine/ext/ndb/tasklets.py", line 362, in _help_tasklet_along
    value
= gen.send(val)
 
File "/base/data/home/apps/s~kobstadendev/1.359392875892326983/items_ndb/items.py", line 439, in get
    user
= self.auth.get_user_by_session()
 
File "/base/python27_runtime/python27_lib/versions/third_party/webapp2-2.5.1/webapp2.py", line 726, in __get__
    value
= self.func(obj)
 
File "/base/data/home/apps/s~kobstadendev/1.359392875892326983/main.py", line 88, in auth
   
return auth.get_auth()
 
File "/base/python27_runtime/python27_lib/versions/third_party/webapp2-2.5.1/webapp2_extras/auth.py", line 623, in get_auth
    request
= request or webapp2.get_request()
 
File "/base/python27_runtime/python27_lib/versions/third_party/webapp2-2.5.1/webapp2.py", line 1720, in get_request
   
assert getattr(_local, 'request', None) is not None, _get_request_error
AssertionError: Request global variable is not set. 
 

Guido van Rossum

unread,
Jun 8, 2012, 10:48:49 AM6/8/12
to web...@googlegroups.com
Do you have a small sample app that reproduces the error?
--
--Guido van Rossum (python.org/~guido)

Jakob Holmelund

unread,
Jun 10, 2012, 12:06:04 PM6/10/12
to webapp2
I think i finally found the culprit for the error :) It definitely has
something to do with the deferred library. Actually i was able to
squash the bug by importing deferred library in the same file as the
BaseHandler, even though it isnt used in that file. To sum it up.
Imagine you have 2 files main.py and test_app.py

main.py:

class BaseHandler(webapp2.RequestHandler):
def render_response(self):
bla bla

@webapp2.cached_property
def auth(self):
return auth.get_auth()
...

test_app.py:

from main import BaseHandler
from google.appengine.ext import deferred

class TestHandler(BaseHandler)
def get(self)
user = self.auth.get_user_by_session()
deferred.defer(...)
...

This will create the Error, the fix is to also import deferred library
in main.py, even if it isnt used there.. so main.py would look like

main.py:

from google.appengine.ext import deferred

class BaseHandler(webapp2.RequestHandler):
def render_response(self):
bla bla

@webapp2.cached_property
def auth(self):
return auth.get_auth()
...

Hope this helps someone else.. And this totally opens up for the
possibility that other libraries could do the same..

On 8 Jun., 16:48, Guido van Rossum <gu...@google.com> wrote:
> Do you have a small sample app that reproduces the error?
>
> On Fri, Jun 8, 2012 at 2:42 AM, Jakob Holmelund
>
>
>
>
>
>
>
>
>
> <jakobholmel...@gmail.com> wrote:
>
> > Hi guys, i really want to get to the bottom of this.
>
> > AssertionError: Request global variable is not set
>
> > I get this error the first time call
>
> > user = self.auth.get_user_by_session()
>
> > after an instance is started. So that means that any user who gets a new instance will run into an error which is not acceptable.
>
> > I have found some earlier threads where this error was produces by importing an app inside a function. I dont think that its the same thing going on here, so if someone has fixed this, please help.
>
> > Im using Python 2.7 and ndb, so i wrap my app with ndb.toplevel like:
>
> > app = ndb.toplevel(webapp2.WSGIApplication(routes.URLS, debug=config.DEBUG, config=config.CONFIG))
>
> > Here is a stack trace of the error
>
> > Request global variable is not set.
> > Traceback (most recent call last):
> >   File "/base/python27_runtime/python27_lib/versions/third_party/webapp2-2.5.1/web app2.py", line 1536, in __call__
> >     rv = self.handle_exception(request, response, e)
> >   File "/base/python27_runtime/python27_lib/versions/third_party/webapp2-2.5.1/web app2.py", line 1530, in __call__
> >     rv = self.router.dispatch(request, response)
> >   File "/base/python27_runtime/python27_lib/versions/third_party/webapp2-2.5.1/web app2.py", line 1278, in default_dispatcher
> >     return route.handler_adapter(request, response)
> >   File "/base/python27_runtime/python27_lib/versions/third_party/webapp2-2.5.1/web app2.py", line 1102, in __call__
> >     return handler.dispatch()
> >   File "/base/data/home/apps/s~kobstadendev/1.359392875892326983/main.py", line 81, in dispatch
> >     webapp2.RequestHandler.dispatch(self)
> >   File "/base/python27_runtime/python27_lib/versions/third_party/webapp2-2.5.1/web app2.py", line 572, in dispatch
> >     return self.handle_exception(e, self.app.debug)
> >   File "/base/python27_runtime/python27_lib/versions/third_party/webapp2-2.5.1/web app2.py", line 570, in dispatch
> >     return method(*args, **kwargs)
> >   File "/base/python27_runtime/python27_lib/versions/1/google/appengine/ext/ndb/ta sklets.py", line 1009, in synctasklet_wrapper
> >     return taskletfunc(*args, **kwds).get_result()
> >   File "/base/python27_runtime/python27_lib/versions/1/google/appengine/ext/ndb/ta sklets.py", line 322, in get_result
> >     self.check_success()
> >   File "/base/python27_runtime/python27_lib/versions/1/google/appengine/ext/ndb/ta sklets.py", line 362, in _help_tasklet_along
> >     value = gen.send(val)
> >   File "/base/data/home/apps/s~kobstadendev/1.359392875892326983/items_ndb/items.p y", line 439, in get
> >     user = self.auth.get_user_by_session()
> >   File "/base/python27_runtime/python27_lib/versions/third_party/webapp2-2.5.1/web app2.py", line 726, in __get__
> >     value = self.func(obj)
> >   File "/base/data/home/apps/s~kobstadendev/1.359392875892326983/main.py", line 88, in auth
> >     return auth.get_auth()
> >   File "/base/python27_runtime/python27_lib/versions/third_party/webapp2-2.5.1/web app2_extras/auth.py", line 623, in get_auth
> >     request = request or webapp2.get_request()
> >   File "/base/python27_runtime/python27_lib/versions/third_party/webapp2-2.5.1/web app2.py", line 1720, in get_request

Guido van Rossum

unread,
Jun 10, 2012, 7:59:12 PM6/10/12
to web...@googlegroups.com
IMO the deferred library is too clever for its own good, and its hacks
cause odd behavior in edge conditions.

But I think there's still something you haven't told us. Does the code
you defer reference main.py? What's in your app.yaml?

Jakob Holmelund

unread,
Jun 11, 2012, 4:41:58 AM6/11/12
to web...@googlegroups.com
Well.. The thing is, that i dont even have to call the deferred library, its enough to just import it. My app.yaml looks like this.

application: sampleapp
version: 1
runtime: python27
api_version: 1
threadsafe: true

libraries:
- name: PIL
  version: latest
- name: webob
  version: latest
- name: jinja2
  version: latest
- name: markupsafe
  version: latest
- name: setuptools
  version: latest
- name: lxml
  version: latest
- name: numpy
  version: latest
- name: webapp2
  version: latest

builtins:
- appstats: on
- deferred: on
- remote_api: on

inbound_services:
- mail
- warmup
- channel_presence

handlers:
- url: /.*
  script: main.app

Im at work now, so forgive me for not adding the sampleapp, but i will get to that later when i get home. Though it looks alot like the code sample i gave before.

Rodrigo Moraes

unread,
Jun 11, 2012, 7:33:31 AM6/11/12
to web...@googlegroups.com
On Sun, Jun 10, 2012 at 8:59 PM, Guido van Rossum wrote:
> IMO the deferred library is too clever for its own good, and its hacks
> cause odd behavior in edge conditions.
>
> But I think there's still something you haven't told us. Does the code
> you defer reference main.py? What's in your app.yaml?

I was scratching my head on Friday because of the same issue.

The problem is that the deferred library instantiates a
WSGIApplication in the module globals, and this resets the 'app' and
'request' thread globals.

My solution was to subclass WSGIApplication and use the subclass
(https://gist.github.com/2909661). Now nobody will interfere with my
custom globals.

This made me think that maybe webapp2 should leave setting globals to
the user, or at least we could hide the current implementation and
document how to make app and request available in a thread safe
manner. These errors are hard to debug and in the current form the
globals can be broken too easily by external libraries. :/

-- rodrigo

Guido van Rossum

unread,
Jun 11, 2012, 12:00:36 PM6/11/12
to web...@googlegroups.com
On Mon, Jun 11, 2012 at 4:33 AM, Rodrigo Moraes
<rodrigo...@gmail.com> wrote:
> On Sun, Jun 10, 2012 at 8:59 PM, Guido van Rossum wrote:
>> IMO the deferred library is too clever for its own good, and its hacks
>> cause odd behavior in edge conditions.

Based on your response and a peek at the code I take this back. In
this case, it's webapp2 that's being too clever. :-)

>> But I think there's still something you haven't told us. Does the code
>> you defer reference main.py? What's in your app.yaml?
>
> I was scratching my head on Friday because of the same issue.
>
> The problem is that the deferred library instantiates a
> WSGIApplication in the module globals, and this resets the 'app' and
> 'request' thread globals.

But instantiating a WSGIApplication as a global is the recommended
pattern when using the Python 2.7 runtime (with WSGI dispatch from
app.yaml) and I find it surprising that just instantiating this class
would have any side effect at all. In a typical app with multiple
handlers specified in app.yaml, there will naturally be multiple
WSGIApplication instances assigned to globals in different modules
(possibly even the same module!) and none of these ought to have
precedence -- that should only happen when a request is received that
is routed to a specific WSGIApplication object.

> My solution was to subclass WSGIApplication and use the subclass
> (https://gist.github.com/2909661). Now nobody will interfere with my
> custom globals.

But the problem is really the reliance of webapp2 on these globals,
right? It's not nice that each app would have to work around this for
itself.

> This made me think that maybe webapp2 should leave setting globals to
> the user, or at least we could hide the current implementation and
> document how to make app and request available in a thread safe
> manner. These errors are hard to debug and in the current form the
> globals can be broken too easily by external libraries. :/

Yeah, something needs to be done -- but it ought to be backward
compatible if at all possible (even though this isn't as bad a problem
with the Python 2.7 module versioning mechanism as it was with the old
Python 2.5 runtime).

Could it be delayed until the request is actually received? Or is that too late?

Rodrigo Moraes

unread,
Jun 11, 2012, 4:21:37 PM6/11/12
to web...@googlegroups.com
On Mon, Jun 11, 2012 at 1:00 PM, Guido van Rossum wrote:
> On Mon, Jun 11, 2012 at 4:33 AM, Rodrigo Moraes
> Based on your response and a peek at the code I take this back. In
> this case, it's webapp2 that's being too clever. :-)

It is. Way too much. Really.

> But instantiating a WSGIApplication as a global is the recommended
> pattern when using the Python 2.7 runtime (with WSGI dispatch from
> app.yaml) and I find it surprising that just instantiating this class
> would have any side effect at all.

Well, the pattern was CGI-style when it was created. The thing is that
webapp2 doesn't expect multiple instantiations of the wsgi app class
in the same request. If you do it twice, it breaks things. This
restriction can be removed. It can be way simpler. But that's how it
is right now. :)

> handlers specified in app.yaml, there will naturally be multiple
> WSGIApplication instances assigned to globals in different modules
> (possibly even the same module!) and none of these ought to have
> precedence -- that should only happen when a request is received that
> is routed to a specific WSGIApplication object.

It sets an app global when the class is instantiated, and when a
request arrives it sets it again. It is kinda silly, because you could
do instead "import main" and then use main.app -- there's your global,
get it directly from the bootstrap file. But the way it is, it really
doesn't allow 2 instantiations of the wsgi app class during the same
request.

> Could it be delayed until the request is actually received? Or is that too late?

The global can be set only for request, removing the "on
instantiation" part. Or the global mechanism can be left to the user.
Anyway, I would like to see this simpler and more explicit.

-- rodrigo

Guido van Rossum

unread,
Jun 11, 2012, 4:24:12 PM6/11/12
to web...@googlegroups.com
Ok, well, I'll leave it up to you to devise a proper fix then. Good luck!

Fabio Sussetto

unread,
Aug 31, 2012, 5:23:45 AM8/31/12
to web...@googlegroups.com
Hi guys,
any luck on this? I'm getting the same annoying issue.

Thomas Marban

unread,
Oct 6, 2012, 6:10:14 PM10/6/12
to web...@googlegroups.com
I solved the issue by including:
from google.appengine.ext import deferred

Jakob Holmelund

unread,
Oct 31, 2012, 3:57:59 PM10/31/12
to web...@googlegroups.com
I see you fixed the bug in the repo.. Will this be added in SDK  1.7.4 ? 

Lindsey Simon

unread,
May 8, 2013, 1:00:51 PM5/8/13
to web...@googlegroups.com
I've tried this - I've added it to all of my py files, but no dice - was there a special place you added it?

Also seems like maybe the fix isn't working since I still have this bug in 1.7.7 if it was known/fixed back near 1.7.4, right?

Lindsey Simon

unread,
May 8, 2013, 1:01:41 PM5/8/13
to web...@googlegroups.com
Can you provide a link that shows where this was fixed? I don't suspect there's any way to fix it in my app such that it would be fixed both in the SDK and in production is there?
Reply all
Reply to author
Forward
0 new messages