Why have I started getting 401 errors, but only with the streaming API, and not the REST API?


#1

I’m using tweepy 1.8, and everything was working fine until some number of days ago. I have the following OAuth-using code:

auth = load_auth()
stream = tweepy.Stream(auth, MyListener())
try: stream.userstream()
except KeyboardInterrupt: raise
except: log.exception('userstream interrupted')

What I see is tweepy.userstream returning None right after I connect. Stepping through with pdb revealed that I’m getting a 401 error. How come?

This error does not occur when using the normal REST API.

I thought this might be transient, but it’s been like this for nearly a week now.

I checked the streaming API to see if anything had changed, but I didn’t notice anything.

Thanks in advance for any help.


#2

Can you trace any of the headers you’re getting back and sending? Do you know if your client is capable of chunked encoding (is it HTTP 1.1 compliant)? Are you sure the access tokens you’re using to connect are valid? When you try them with the REST API, are you trying them against methods that REQUIRE authentication rather than just support it?


#3

Hi @episod,

The headers:

(Pdb) p resp.getheaders() [('content-length', '1285'), ('server', 'Jetty(6.1.25)'), ('content-type', 'text/html; charset=iso-8859-1'), ('www-authenticate', 'Basic realm="Firehose"'), ('cache-control', 'must-revalidate,no-cache,no-store')]

The content:

Error 401 UNAUTHORIZED

HTTP ERROR: 401

Problem accessing /2/user.json. Reason:

    UNAUTHORIZED

Powered by Jetty://

The client is tweepy. I’m not sure, but the relevant code just uses plain httplib:

            if self.scheme == "http":
                conn = httplib.HTTPConnection(self.host)
            else:
                conn = httplib.HTTPSConnection(self.host)  # i've been invoking this path
            self.auth.apply_auth(url, 'POST', self.headers, self.parameters)
            conn.connect()
            conn.sock.settimeout(self.timeout)
            conn.request('POST', self.url, self.body, headers=self.headers)
            resp = conn.getresponse()

That said, the resp object seems to have a ‘_read_chunked’ method:

(Pdb) p resp (Pdb) dir(resp) ['__doc__', '__init__', '__module__', '_check_close', '_method', '_read_chunked', '_read_status', '_safe_read', 'begin', 'chunk_left', 'chunked', 'close', 'debuglevel', 'fp', 'getheader', 'getheaders', 'isclosed', 'length', 'msg', 'read', 'reason', 'status', 'strict', 'version', 'will_close']

I know that the access tokens I’m using had worked for a while before they suddenly stopped working without explanation. I also know that I continue to be able to use them fine for the REST API, which I’m using like so from tweepy (note that this reuses the same load_auth() as the streaming code snippet from my first post):

auth = load_auth() api = tweepy.API(auth)

On the REST API, I have been using methods for which auth is optional, but (1) I would not be able to make as many calls if I wasn’t authenticated (I used to make public calls before I quickly hit the rate ceiling), and (2) just now I tried with a method for which auth is required (/blocks/blocking):

In [2]: api.api.blocks() Out[2]: [, , , , , , ...

Please let me know if you require any further information. Thanks in advance for any help.


#4

Sigh. This appears to have gone away on its own, just as mysteriously as it appeared.


#5

The same problem here! Mysteriously it appeared, and it is being difficult to track it. Only User Stream is returning me 401. The REST API works ok.

My headers are

Content-Type: text/html
WWW-Authenticate: Basic realm="Firehose"
Cache-Control: must-revalidate,no-cache,no-store
Content-Length: 1505
Connection: close


#6

Recently I have faced with the same issue as @yaaang and @educompsci had.
After 1 day of researches I finally found the problem.
It was a lack of oauth_version parameter in OAuth sign.

I guess REST API does not require this parameter, but streaming API does!

So guys, make sure that you have this parameter in your headers.


#7

Same problem here.

The request:

POST /1/statuses/sample.json HTTP/1.1
Authorization: OAuth oauth_token="…", oauth_consumer_key="…", oauth_version=“1.0”, oauth_signature_method=“HMAC-SHA1”, oauth_timestamp="…", oauth_nonce="…", oauth_signature="…"
Content-Length: 10
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Host: stream.twitter.com
Connection: Keep-Alive
User-Agent: Apache-HttpClient/4.0.1 (java 1.5)
Expect: 100-Continue

“track=java”

The response:

HTTP/1.1 401 Unauthorized
Content-Type: text/html
WWW-Authenticate: Basic realm="Firehose"
Cache-Control: must-revalidate,no-cache,no-store
Content-Length: 1241
Connection: close


#8

/1/statuses/sample.json doesn’t accept POST requests nor parameters such as track=java – are you looking for /1/statuses/filter.json on stream.twitter.com instead?