Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Error: Unable to store the password for poetry-repository-pypi in the key ring: Failed to unlock the collection! #2692

Closed
joaqo opened this issue Jul 20, 2020 · 30 comments
Labels
status/duplicate Duplicate issues

Comments

@joaqo
Copy link

joaqo commented Jul 20, 2020

Hi, I am getting [KeyRingError] Unable to store the password for poetry-repository-pypi in the key ring: Failed to unlock the collection! when running:

poetry config pypi-token.pypi <MY PYPI TOKEN>

Searched for this error everywhere but couldn't find anything. Running on the last version of Poetry and Ubuntu 18.04 LTS.

Also, if I set the token using an environment variable I get: Unable to retrieve the password for poetry-repository-pypi from the key ring.

@joaqo joaqo added kind/bug Something isn't working as expected status/triage This issue needs to be triaged labels Jul 20, 2020
@abn
Copy link
Member

abn commented Jul 21, 2020

Can you try unlocking the collection using something like Seahorse?

Usually this happens when your keyring was left locked after login etc. Manual unlocks and/or reboots are known fix this issue. Note that this has nothing to do with poetry or how it interacts with the OS keyring.

@earonesty
Copy link

Why does poetry need the keyring? Is it possible to build/deploy in CI/CD without using a keyring?

@abn
Copy link
Member

abn commented Sep 4, 2020

@earonesty poetry uses keyring for storing credentials. It is entirely possible to build/deploy in CI/CD without any issues.

- name: Publish to PyPI
env:
POETRY_PYPI_TOKEN_PYPI: ${{ secrets.PYPI_TOKEN }}
run: |
source $HOME/.poetry/env
poetry run poetry publish

@abn abn added the area/docs/faq Frequently duplicated/potential addition to FAQ label Oct 1, 2020
@abn
Copy link
Member

abn commented Oct 1, 2020

@python-poetry/triage we should consider providing a error solution exception via crashtest or implement an option to skip keyring on failure when writing l; and warn in both write and read cases where this fails.

@randallpittman
Copy link

randallpittman commented Aug 11, 2021

I have this problem with keyring working with Seahorse or something if I'm logged into a remote machine over ssh. If I log in with X2Go instead of getting an error it just freezes... 🤷🏼‍♂️ Will return with more info if I get any.

EDIT 1: I get this error "Failed to unlock the collection!" if I try to use keyring in the following manner while logged into a remote machine (Linux Mint 20 XFCE, Seahorse is the password manager):

import keyring
keyring.set_password("poetry-repository-testpypi", "__token__", "<my-testpypi-key>"

So I guess keyring doesn't work over SSH? I'll look into the issues over at jaraco/keyring.

EDIT 2: The README at jaraco/keyring provides instructions for running keyring on a headless system. This seems like quite a bit of hassle and very non-obvious for poetry users.

@g8rpal
Copy link

g8rpal commented Aug 17, 2021

this fixed it for me... https://blog.frank-mich.com/python-poetry-1-0-0-private-repo-issue-fix/

@earonesty
Copy link

earonesty commented Nov 5, 2021

@earonesty poetry uses keyring for storing credentials. It is entirely possible to build/deploy in CI/CD without any issues.

right, but why bother storing credentials? i don't want it to.

  • tried setting POETRY_PYPI_TOKEN_PYPI to a valid token... didn't help... still wants my keyring
  • seems like it should try reading from ~/.pypirc like twine does...
  • poetry config and its sundry ways could be mentioned in the error messages?
  • tried the config - was "unable to unlock the collection" & how to turn off keyring support, so it will fall back?
  • messed with dbus env vars... poetry decided to store stuff plain text.... which worked! but when i log in again, it goes back to failing to use the keyring unless i kill my dbus settings again
  • sticking it on the command line works, but then i have to worry about my bash log

@strongbugman
Copy link

well, maybe a permission problem, with "sudo" save me in this case

@ypicard
Copy link

ypicard commented Dec 23, 2021

Poetry strikes again 💣

@KafCoppelia
Copy link

KafCoppelia commented Jan 17, 2022

Similar error occured when I was using poetry build then poetry publish to publish my python project to PYPI.🤔
But yesterday before the problem ocurred Poetry did in normal.

KeyRingError

Unable to retrieve the password for poetry-repository-pypi from the key ring

at ~/.local/share/pypoetry/venv/lib/python3.8/site-packages/poetry/utils/password_manager.py:39 in get_password
35│
36│ try:
37│ return keyring.get_password(name, username)
38│ except (RuntimeError, keyring.errors.KeyringError):
→ 39│ raise KeyRingError(
40│ "Unable to retrieve the password for {} from the key ring".format(name)
41│ )
42│
43│ def set_password(self, name, username, password):

@KafCoppelia
Copy link

Oh fixed it today by using poetry config http-basic.pypi username password.

@MasterMedo
Copy link

sudo pacman -S gnome-keyring solved it for me.

@UltiRequiem
Copy link

sudo pacman -S gnome-keyring

This, but is not cool to have to install something of gnome if you are not using gnome...

@Cardu
Copy link

Cardu commented Feb 17, 2022

Had the same problem in a container, solved it by setting the null keyring within the underlying lib, it's just an env variable:

PYTHON_KEYRING_BACKEND: keyring.backends.null.Keyring

see https://pypi.org/project/keyring/ disabling keyring

@KafCoppelia
Copy link

OK keyringerror again. Then fixed it by keyring --disable in terminal on Ubuntu. Then poetry publish --build as usual OK!

@pyalchy1
Copy link

Why does poetry need the keyring? Is it possible to build/deploy in CI/CD without using a keyring?

I'm quite curious about this as well actually.

#2692 (comment)

I can't remember ever having to install any package with root permissions. Infact, If I remember correctly, pip specifically warns against it.

Also, why exactly does poetry modify the error Traceback?

sigh I have other questions, but mainly why does poetry even request access from the keyring in the first place?

@sanderland
Copy link

Installing keyrings.alt fixed this for me. The problem was that only keyrings.google-artifactregistry-auth was available, which does not have a set_password

@earonesty
Copy link

this works to evade the keyring, and is appropriate for ci/cd

POETRY_HTTP_BASIC_TEST_USERNAME=__token__
POETRY_HTTP_BASIC_TEST_PASSWORD=pypi-secret

@pronovic
Copy link

pronovic commented Sep 2, 2022

I'm running into a similar error with Poetry v1.2.0 for simple operations like installing a plugin in my Debian development environment. I'm not sure whether this is exactly the same issue as described above or just results in a similar error message.

$ poetry self add poetry-dynamic-versioning-plugin
Failed to unlock the collection!

This seems to have happened because I was SSH'd into my development environment, which has the GNOME Keyring installed. When I RDP'd in so I would have an X session, then the GNOME keyring dialog popped up to unlock the keyring. On the surface, it doesn't seem like there's any need for the keyring in this situation, because I'm installing a public plugin. It seems like maybe there's a code path where Poetry attempts to unlock the keyring even if it's not going to be needed.

I don't get this error on Windows or MacOS, although it's possible that a keyring is just silently being unlocked under the covers on those platforms, and I don't notice because it's not failing.

My workaround is to explicitly set a null keyring as suggested in @Cardu 's comment above, in Poetry issue #6277, and also in pip issue #6773:

$ PYTHON_KEYRING_BACKEND="keyring.backends.null.Keyring" poetry self add poetry-dynamic-versioning-plugin

I also confirmed that keyring --disable works as in @KafCoppelia 's suggestion. However, I don't like that solution for my use case, because it permanently disables the keyring in configuration, and I do need the keyring available for other things.

@shyney7
Copy link

shyney7 commented Sep 8, 2022

Im also getting this error on my Debian Distro when trying to configure a new project with poetry init. When trying to specify the dependencies it fails with the following errors:

Package to add or search for (leave blank to skip): pydrive
[urllib3.connectionpool] Starting new HTTPS connection (1): pypi.org:443
[urllib3.connectionpool] https://pypi.org:443 "GET /search?q=pydrive HTTP/1.1" 301 215
[urllib3.connectionpool] https://pypi.org:443 "GET /search/?q=pydrive HTTP/1.1" 200 23369
Found 20 packages matching pydrive
Showing the first 10 matches

Enter package # to add, or the complete package name if it is not listed []:
 [ 0] PyDrive
 [ 1] PyDrive3
 [ 2] PyDrive2
 [ 3] pydriver
 [ 4] pydriveziead
 [ 5] pydrivedol
 [ 6] drivelib
 [ 7] GsuiteToMd
 [ 8] yagdrive
 [ 9] free-storage
 [10] 
 > 0
Enter the version constraint to require (or leave blank to use the latest version): 
[keyring.backend] Loading KWallet
[keyring.backend] Loading SecretService
[keyring.backend] Loading Windows
[keyring.backend] Loading chainer
[keyring.backend] Loading libsecret
[keyring.backend] Loading macOS

  Stack trace:

  29  ~/.local/share/pypoetry/venv/lib/python3.7/site-packages/cleo/application.py:329 in run
       327│ 
       328│             try:
     → 329│                 exit_code = self._run(io)
       330│             except Exception as e:
       331│                 if not self._catch_exceptions:

  28  ~/.local/share/pypoetry/venv/lib/python3.7/site-packages/poetry/console/application.py:185 in _run
       183│         self._load_plugins(io)
       184│ 
     → 185│         exit_code: int = super()._run(io)
       186│         return exit_code
       187│ 

  27  ~/.local/share/pypoetry/venv/lib/python3.7/site-packages/cleo/application.py:423 in _run
       421│             io.input.set_stream(stream)
       422│ 
     → 423│         exit_code = self._run_command(command, io)
       424│         self._running_command = None
       425│ 

  26  ~/.local/share/pypoetry/venv/lib/python3.7/site-packages/cleo/application.py:465 in _run_command
       463│ 
       464│         if error is not None:
     → 465│             raise error
       466│ 
       467│         return event.exit_code

  25  ~/.local/share/pypoetry/venv/lib/python3.7/site-packages/cleo/application.py:449 in _run_command
       447│ 
       448│             if event.command_should_run():
     → 449│                 exit_code = command.run(io)
       450│             else:
       451│                 exit_code = ConsoleCommandEvent.RETURN_CODE_DISABLED

  24  ~/.local/share/pypoetry/venv/lib/python3.7/site-packages/cleo/commands/base_command.py:119 in run
       117│         io.input.validate()
       118│ 
     → 119│         status_code = self.execute(io)
       120│ 
       121│         if status_code is None:

  23  ~/.local/share/pypoetry/venv/lib/python3.7/site-packages/cleo/commands/command.py:83 in execute
        81│ 
        82│         try:
     →  83│             return self.handle()
        84│         except KeyboardInterrupt:
        85│             return 1

  22  ~/.local/share/pypoetry/venv/lib/python3.7/site-packages/poetry/console/commands/init.py:188 in handle
       186│                 help_displayed = True
       187│             requirements.update(
     → 188│                 self._format_requirements(self._determine_requirements([]))
       189│             )
       190│             if self.io.is_interactive():

  21  ~/.local/share/pypoetry/venv/lib/python3.7/site-packages/poetry/console/commands/init.py:338 in _determine_requirements
       336│                     if package_constraint is None:
       337│                         _, package_constraint = self._find_best_version_for_package(
     → 338│                             package
       339│                         )
       340│ 

  20  ~/.local/share/pypoetry/venv/lib/python3.7/site-packages/poetry/console/commands/init.py:399 in _find_best_version_for_package
       397│         selector = VersionSelector(self._get_pool())
       398│         package = selector.find_best_candidate(
     → 399│             name, required_version, allow_prereleases=allow_prereleases, source=source
       400│         )
       401│ 

  19  ~/.local/share/pypoetry/venv/lib/python3.7/site-packages/poetry/version/version_selector.py:39 in find_best_candidate
        37│             },
        38│         )
     →  39│         candidates = self._pool.find_packages(dependency)
        40│         only_prereleases = all(c.version.is_unstable() for c in candidates)
        41│ 

  18  ~/.local/share/pypoetry/venv/lib/python3.7/site-packages/poetry/repositories/pool.py:181 in find_packages
       179│         packages = []
       180│         for repo in self._repositories:
     → 181│             packages += repo.find_packages(dependency)
       182│ 
       183│         return packages

  17  ~/.local/share/pypoetry/venv/lib/python3.7/site-packages/poetry/repositories/repository.py:46 in find_packages
        44│         ignored_pre_release_packages = []
        45│ 
     →  46│         for package in self._find_packages(dependency.name, constraint):
        47│             if package.yanked and not isinstance(constraint, Version):
        48│                 # PEP 592: yanked files are always ignored, unless they are the only

  16  ~/.local/share/pypoetry/venv/lib/python3.7/site-packages/poetry/repositories/pypi_repository.py:116 in _find_packages
       114│         """
       115│         try:
     → 116│             info = self.get_package_info(name)
       117│         except PackageNotFound:
       118│             self._log(

  15  ~/.local/share/pypoetry/venv/lib/python3.7/site-packages/poetry/repositories/pypi_repository.py:105 in get_package_info
       103│ 
       104│         package_info: dict[str, Any] = self._cache.store("packages").remember_forever(
     → 105│             name, lambda: self._get_package_info(name)
       106│         )
       107│         return package_info

  14  ~/.local/share/pypoetry/venv/lib/python3.7/site-packages/cachy/repository.py:174 in remember_forever
       172│             return val
       173│ 
     → 174│         val = value(callback)
       175│ 
       176│         self.forever(key, val)

  13  ~/.local/share/pypoetry/venv/lib/python3.7/site-packages/cachy/helpers.py:6 in value
         4│ def value(val):
         5│     if callable(val):
     →   6│         return val()
         7│ 
         8│     return val

  12  ~/.local/share/pypoetry/venv/lib/python3.7/site-packages/poetry/repositories/pypi_repository.py:105 in <lambda>
       103│ 
       104│         package_info: dict[str, Any] = self._cache.store("packages").remember_forever(
     → 105│             name, lambda: self._get_package_info(name)
       106│         )
       107│         return package_info

  11  ~/.local/share/pypoetry/venv/lib/python3.7/site-packages/poetry/repositories/pypi_repository.py:155 in _get_package_info
       153│ 
       154│     def _get_package_info(self, name: NormalizedName) -> dict[str, Any]:
     → 155│         data = self._get(f"pypi/{name}/json")
       156│         if data is None:
       157│             raise PackageNotFound(f"Package [{name}] not found.")

  10  ~/.local/share/pypoetry/venv/lib/python3.7/site-packages/poetry/repositories/pypi_repository.py:244 in _get
       242│                 self._base_url + endpoint,
       243│                 raise_for_status=False,
     → 244│                 timeout=REQUESTS_TIMEOUT,
       245│             )
       246│         except requests.exceptions.TooManyRedirects:

   9  ~/.local/share/pypoetry/venv/lib/python3.7/site-packages/poetry/utils/authenticator.py:246 in get
       244│ 
       245│     def get(self, url: str, **kwargs: Any) -> requests.Response:
     → 246│         return self.request("get", url, **kwargs)
       247│ 
       248│     def post(self, url: str, **kwargs: Any) -> requests.Response:

   8  ~/.local/share/pypoetry/venv/lib/python3.7/site-packages/poetry/utils/authenticator.py:187 in request
       185│     ) -> requests.Response:
       186│         request = requests.Request(method, url)
     → 187│         credential = self.get_credentials_for_url(url)
       188│ 
       189│         if credential.username is not None or credential.password is not None:

   7  ~/.local/share/pypoetry/venv/lib/python3.7/site-packages/poetry/utils/authenticator.py:310 in get_credentials_for_url
       308│                 # no credentials were provided in the url, try finding the
       309│                 # best repository configuration
     → 310│                 self._credentials[url] = self._get_credentials_for_url(url)
       311│             else:
       312│                 # Split from the right because that's how urllib.parse.urlsplit()

   6  ~/.local/share/pypoetry/venv/lib/python3.7/site-packages/poetry/utils/authenticator.py:272 in _get_credentials_for_url
       270│         credential = (
       271│             self._get_credentials_for_repository(repository=repository)
     → 272│             if repository is not None
       273│             else HTTPAuthCredential()
       274│         )

   5  ~/.local/share/pypoetry/venv/lib/python3.7/site-packages/poetry/utils/authenticator.py:260 in _get_credentials_for_repository
       258│         if key not in self._credentials:
       259│             self._credentials[key] = repository.get_http_credentials(
     → 260│                 password_manager=self._password_manager, username=username
       261│             )
       262│ 

   4  ~/.local/share/pypoetry/venv/lib/python3.7/site-packages/poetry/utils/authenticator.py:91 in get_http_credentials
        89│             # fallback to url and netloc based keyring entries
        90│             credential = password_manager.keyring.get_credential(
     →  91│                 self.url, self.netloc, username=credential.username
        92│             )
        93│ 

   3  ~/.local/share/pypoetry/venv/lib/python3.7/site-packages/poetry/utils/password_manager.py:51 in get_credential
        49│ 
        50│         for name in names:
     →  51│             credential = keyring.get_credential(name, username)
        52│             if credential:
        53│                 return HTTPAuthCredential(

   2  ~/.local/share/pypoetry/venv/lib/python3.7/site-packages/keyring/core.py:72 in get_credential
        70│ ) -> typing.Optional[credentials.Credential]:
        71│     """Get a Credential for the specified service."""
     →  72│     return get_keyring().get_credential(service_name, username)
        73│ 
        74│ 

   1  ~/.local/share/pypoetry/venv/lib/python3.7/site-packages/keyring/backends/SecretService.py:112 in get_credential
       110│         scheme = self.schemes[self.scheme]
       111│         query = self._query(service, username)
     → 112│         collection = self.get_preferred_collection()
       113│ 
       114│         with closing(collection.connection):

  KeyringLocked

  Failed to unlock the collection!

  at ~/.local/share/pypoetry/venv/lib/python3.7/site-packages/keyring/backends/SecretService.py:67 in get_preferred_collection
       63│             raise InitError("Failed to create the collection: %s." % e)
       64│         if collection.is_locked():
       65│             collection.unlock()
       66│             if collection.is_locked():  # User dismissed the prompt
    →  67│                 raise KeyringLocked("Failed to unlock the collection!")
       68│         return collection
       69│ 
       70│     def unlock(self, item):
       71│         if hasattr(item, 'unlock'):

@maciejskorski
Copy link

maciejskorski commented Sep 10, 2022

Also happens to me when connecting via SSH, and my workaround is to disable keyring within a sufficient scope, as poetry can work without keyring.

My two cents are that this behaviour is not consistent with the docs.
The documentation promises a backup in case of keyring failure:

If a system keyring is available and supported, the password is stored to and retrieved from the keyring... 
If access to keyring fails or is unsupported, this will **fall back to writing the password to the auth.toml** file along with the username.

Of course, it may well be an issue on the keyring side (locked, not set up properly...), but would be nice to fall back gracefully. A bit odd, but sometimes poetry depends on keyring even for password-free operations in config:

(.venv) azureuser@sense-mskorski:~/projects/test_project$ poetry config virtualenvs.create false


  KeyRingError

  Unable to retrieve the password for poetry-repository-my_private_repo from the key ring

EDIT: the keyring usage is handled in poetry.utils.password_manager and has improved a bit since in version 1.2, in particular with respect to null backends.

def _check(self) -> None:
try:
import keyring
except Exception as e:
logger.debug(f"An error occurred while importing keyring: {e!s}")
self._is_available = False
return
backend = keyring.get_keyring()
name = backend.name.split(" ")[0]
if name in ("fail", "null"):
logger.debug("No suitable keyring backend found")
self._is_available = False
elif "plaintext" in backend.name.lower():
logger.debug("Only a plaintext keyring backend is available. Not using it.")
self._is_available = False
elif name == "chainer":
try:
import keyring.backend
backends = keyring.backend.get_all_keyring()
self._is_available = any(
b.name.split(" ")[0] not in ["chainer", "fail", "null"]
and "plaintext" not in b.name.lower()
for b in backends
)
except Exception:
self._is_available = False
if not self._is_available:
logger.debug("No suitable keyring backends were found")

@neersighted
Copy link
Member

Closing as duplicate of #1917

@neersighted neersighted added status/duplicate Duplicate issues and removed kind/bug Something isn't working as expected status/triage This issue needs to be triaged area/docs/faq Frequently duplicated/potential addition to FAQ labels Sep 20, 2022
@EKami
Copy link

EKami commented Nov 5, 2022

Had the same problem in a container, solved it by setting the null keyring within the underlying lib, it's just an env variable:

PYTHON_KEYRING_BACKEND: keyring.backends.null.Keyring

see https://pypi.org/project/keyring/ disabling keyring

This, easiest solution and worked perfectly

@LuckCky
Copy link

LuckCky commented Nov 15, 2022

I ran into same issue after updating Poetry from 1.1.xxx to 1.2.2 on Mac BigSur.
Before the update it was fine, but after Poetry couldn't read keychain file
I advise you not to disable keyring and store password in auth.toml as it is stored plaintext!
What helped me was to allow read Poetry's keychain file by any application and then return to ask for access and add python to allowed apps again.
Hope this helps you and saves you some time

@neersighted neersighted closed this as not planned Won't fix, can't repro, duplicate, stale Nov 15, 2022
@SheepyBloke-OPO
Copy link

I have a Mac, and I needed to delete an old password in the Keychain in order to get it to work. I went to the Keychain Access app, navigated to the login default keychain and filtered on Passwords. In there was one called poetry-repositor-***, where *** was my private repo. Deleting that and running poetry config http-basic.<PRIVATE-REPO> <USER> <TOKEN> again solved this issue for me.

@Slanman3755
Copy link

Just to add to the macos solutions above: the Issue for me was that the key is added to the keychain with access only allowed by a specific python version. When I switched python versions then the poetry config command started failing. The solution is to allow all apps on the poetry keys or add the additional python versions you need. Ideally poetry would handle this or at least provide a better error message.

@niftynei
Copy link

niftynei commented Jul 8, 2023

fwiw, i found this really helpful for getting into my keyring on a remote box (jammy/ubuntu) with gnome-keyring installed: https://unix.stackexchange.com/a/602935

note that you have to source the file every time to get it to run correctly.

@tlatrace
Copy link

tlatrace commented Feb 7, 2024

[MacOS]
I have the same keyring issue with poetry installed with pip.
Un-installing poetry with pip and re-install it with brew this time solved the issue on my side.

@srinivaskumarramdas
Copy link

On macOs:
python -m keyring --disable
and
poetry config pypi-token.pypi <MY PYPI TOKEN> worked for me.

Copy link

github-actions bot commented Apr 5, 2024

This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Apr 5, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
status/duplicate Duplicate issues
Projects
None yet
Development

No branches or pull requests