简体   繁体   中英

Pymongo KeyError: '$err' MongoDB Atlas

I'm following this https://www.mongodb.com/blog/post/getting-started-with-python-and-mongodb introductory tutorial. I can connect to the cluster fine with mongo shell, but not with pymongo (Python: 3.6.1, Pymongo 3.4.0). Pymongo works okay with a local mongodb. What is the problem? Below is the exception I get:

----------------------------------------------------------------------
-----
KeyError                                  Traceback (most recent call 
last)
<ipython-input-22-1c9d47341338> in <module>()
----> 1 server_status_result = db.command('serverStatus')
      2 pprint(server_status_result)

/home/tim/.virtualenvs/main/lib/python3.6/site-
packages/pymongo/database.py in command(self, command, value, check, 
allowable_errors, read_preference, codec_options, **kwargs)
489         """
490         client = self.__client
--> 491         with client._socket_for_reads(read_preference) as 
(sock_info, slave_ok):
492             return self._command(sock_info, command, slave_ok, 
value,
493                                  check, allowable_errors, 
read_preference,

/usr/lib/python3.6/contextlib.py in __enter__(self)
 80     def __enter__(self):
 81         try:
---> 82             return next(self.gen)
 83         except StopIteration:
 84             raise RuntimeError("generator didn't yield") from None

/home/tim/.virtualenvs/main/lib/python3.6/site-
packages/pymongo/mongo_client.py in _socket_for_reads(self, 
read_preference)
857         topology = self._get_topology()
858         single = topology.description.topology_type == 
TOPOLOGY_TYPE.Single
--> 859         with self._get_socket(read_preference) as sock_info:
860             slave_ok = (single and not sock_info.is_mongos) or (
861                 preference != ReadPreference.PRIMARY)

/usr/lib/python3.6/contextlib.py in __enter__(self)
 80     def __enter__(self):
 81         try:
---> 82             return next(self.gen)
 83         except StopIteration:
 84             raise RuntimeError("generator didn't yield") from None

/home/tim/.virtualenvs/main/lib/python3.6/site-
packages/pymongo/mongo_client.py in _get_socket(self, selector)
823         server = self._get_topology().select_server(selector)
824         try:
--> 825             with server.get_socket(self.__all_credentials) as 
sock_info:
826                 yield sock_info
827         except NetworkTimeout:

/usr/lib/python3.6/contextlib.py in __enter__(self)
 80     def __enter__(self):
 81         try:
---> 82             return next(self.gen)
 83         except StopIteration:
 84             raise RuntimeError("generator didn't yield") from None

/home/tim/.virtualenvs/main/lib/python3.6/site-
packages/pymongo/server.py in get_socket(self, all_credentials, 
checkout)
166     @contextlib.contextmanager
167     def get_socket(self, all_credentials, checkout=False):
--> 168         with self.pool.get_socket(all_credentials, checkout) 
as sock_info:
169             yield sock_info
170 

/usr/lib/python3.6/contextlib.py in __enter__(self)
 80     def __enter__(self):
 81         try:
---> 82             return next(self.gen)
 83         except StopIteration:
 84             raise RuntimeError("generator didn't yield") from None

/home/tim/.virtualenvs/main/lib/python3.6/site-
packages/pymongo/pool.py in get_socket(self, all_credentials, 
checkout)
790         sock_info = self._get_socket_no_auth()
791         try:
--> 792             sock_info.check_auth(all_credentials)
793             yield sock_info
794         except:

/home/tim/.virtualenvs/main/lib/python3.6/site-
packages/pymongo/pool.py in check_auth(self, all_credentials)
510 
511             for credentials in cached - authset:
--> 512                 auth.authenticate(credentials, self)
513                 self.authset.add(credentials)
514 

/home/tim/.virtualenvs/main/lib/python3.6/site-
packages/pymongo/auth.py in authenticate(credentials, sock_info)
468     mechanism = credentials.mechanism
469     auth_func = _AUTH_MAP.get(mechanism)
--> 470     auth_func(credentials, sock_info)
471 
472 

/home/tim/.virtualenvs/main/lib/python3.6/site-
packages/pymongo/auth.py in _authenticate_default(credentials, 
sock_info)
448 def _authenticate_default(credentials, sock_info):
449     if sock_info.max_wire_version >= 3:
--> 450         return _authenticate_scram_sha1(credentials, 
sock_info)
451     else:
452         return _authenticate_mongo_cr(credentials, sock_info)

/home/tim/.virtualenvs/main/lib/python3.6/site-
packages/pymongo/auth.py in _authenticate_scram_sha1(credentials, 
sock_info)
227                ('conversationId', res['conversationId']),
228                ('payload', Binary(client_final))])
--> 229     res = sock_info.command(source, cmd)
230 
231     parsed = _parse_scram_response(res['payload'])

/home/tim/.virtualenvs/main/lib/python3.6/site-
packages/pymongo/pool.py in command(self, dbname, spec, slave_ok, 
read_preference, codec_options, check, allowable_errors, check_keys, 
read_concern, write_concern, parse_write_concern_error, collation)
422         # Catch socket.error, KeyboardInterrupt, etc. and close 
ourselves.
423         except BaseException as error:
--> 424             self._raise_connection_failure(error)
425 
426     def send_message(self, message, max_doc_size):

/home/tim/.virtualenvs/main/lib/python3.6/site-
packages/pymongo/pool.py in _raise_connection_failure(self, error)
550             _raise_connection_failure(self.address, error)
551         else:
--> 552             raise error
553 
554     def __eq__(self, other):

/home/tim/.virtualenvs/main/lib/python3.6/site-
packages/pymongo/pool.py in command(self, dbname, spec, slave_ok, 
read_preference, codec_options, check, allowable_errors, check_keys, 
read_concern, write_concern, parse_write_concern_error, collation)
417                            read_concern,
418                            
parse_write_concern_error=parse_write_concern_error,
--> 419                            collation=collation)
420         except OperationFailure:
421             raise

/home/tim/.virtualenvs/main/lib/python3.6/site-p 
ackages/pymongo/network.py in command(sock, dbname, spec, slave_ok, 
is_mongos, read_preference, codec_options, check, allowable_errors, 
address, check_keys, listeners, max_bson_size, read_concern, 
parse_write_concern_error, collation)
108         response = receive_message(sock, 1, request_id)
109         unpacked = helpers._unpack_response(
--> 110             response, codec_options=codec_options)
111 
112         response_doc = unpacked['data'][0]

/home/tim/.virtualenvs/main/lib/python3.6/site-
packages/pymongo/helpers.py in _unpack_response(response, cursor_id, 
codec_options)
126         # Fake the ok field if it doesn't exist.
127         error_object.setdefault("ok", 0)
--> 128         if error_object["$err"].startswith("not master"):
129             raise NotMasterError(error_object["$err"], 
error_object)
130         elif error_object.get("code") == 50:

KeyError: '$err'

I believe this is an Atlas bug, I've reported it to the team. The bug is, if you fail to log in to Atlas because your username or password are incorrect, it replies in a way that makes PyMongo throw a KeyError instead of the proper OperationFailure("auth failed") .

PyMongo does work with Atlas, however, if you properly format your connection string with your username and password. Make sure your username and password are URL-quoted. Substitute your username and password into this Python code:

from urllib import quote_plus

print(quote_plus('MY USERNAME'))
print(quote_plus('MY PASSWORD'))

Take the output and put it into the connection string Atlas gave you, eg if your username is jesse@example.com and your password is "foo:bar", put that in the first part of the string, and get the rest of the string from the Atlas control panel for your account:

mongodb://jesse%40example.com:foo%3Abar/@cluster0-shard-00-00-abc.mongodb.net:27017,cluster0-shard-00-01-abc.mongodb.net:27017,cluster0-shard-00-02-abc.mongodb.net:27017/test?ssl=true&replicaSet=Cluster0-shard-0&authSource=admin

Note how "jesse@example.com" has become "jesse%40example.com", and "foo:bar" has become "foo%3Abar".

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM