Poetry update does not error out on non-existent dependencies
Description
poetry update will happily accept any and all names given to it with no complaints, even if they're not declared dependencies of the current project. This is very confusing, as it makes it look like an action succeeded if a mistake or typo sneaks in, when in reality it had no effect.
Example:
$ poetry update none of this is a real package
Updating dependencies
Resolving dependencies... (0.3s)
No dependencies to install or update
This also means it's not possible to request an update of a dependency to a specific version, because it will simply be taken as a non-existent dependency name and ignored, rather than a name + version:
$ poetry update "example==0.2.0"
Updating dependencies
Resolving dependencies... (0.5s)
No dependencies to install or update
The user thus has no way to influence the locking decisions being made, and is entirely at the mercy of what happens to be in the available indices at the instant the command was run. Being able to control what version is being locked to is very important for the infrequent, but critical case when a specific dependency's latest release is broken, and a temporary override to an older version is required. Currently, it seems there's no way to do it, short of changing the declared dependency version via the add command, which should not be required.
Workarounds
No.
Poetry Installation Method
pipx
Operating System
Ubuntu 24.04
Poetry Version
Poetry (version 2.1.3)
Poetry Configuration
cache-dir = "/home/mkatafiasz/.cache/pypoetry"
data-dir = "/home/mkatafiasz/.local/share/pypoetry"
installer.max-workers = null
installer.no-binary = null
installer.only-binary = null
installer.parallel = true
installer.re-resolve = true
keyring.enabled = true
python.installation-dir = "{data-dir}/python" # /home/mkatafiasz/.local/share/pypoetry/python
repositories.artifactory.url = "https://private/artifactory/api/pypi/repo"
requests.max-retries = 0
solver.lazy-wheel = true
system-git-client = false
virtualenvs.create = true
virtualenvs.in-project = null
virtualenvs.options.always-copy = false
virtualenvs.options.no-pip = false
virtualenvs.options.system-site-packages = false
virtualenvs.path = "{cache-dir}/virtualenvs" # /home/mkatafiasz/.cache/pypoetry/virtualenvs
virtualenvs.prompt = "{project_name}-py{python_version}"
virtualenvs.use-poetry-python = false
Python Sysconfig
No response
Example pyproject.toml
Poetry Runtime Logs
poetry-runtime.log
Loading configuration file /home/mkatafiasz/.config/pypoetry/config.toml
Loading configuration file /home/mkatafiasz/.config/pypoetry/auth.toml
Adding repository artifactory (https://mkatafiasz:xxxx@private/artifactory/api/pypi/repo/simple) and setting it as supplemental
Using virtualenv: /home/mkatafiasz/.cache/pypoetry/virtualenvs/example-supervisor-8QUTkN6H-py3.12
Checking keyring availability: Checking if keyring is available
[keyring:keyring.backend] Loading KWallet
[keyring:keyring.backend] Loading SecretService
[keyring:keyring.backend] Loading Windows
[keyring:keyring.backend] Loading chainer
[keyring:keyring.backend] Loading libsecret
[keyring:keyring.backend] Loading macOS
Using keyring backend 'SecretService Keyring'
Available
Updating dependencies
Resolving dependencies...
1: fact: example-supervisor is 0.2.0
1: derived: example-supervisor
1: fact: example-supervisor depends on fastapi[standard] (>=0.115.12,<0.116.0)
1: fact: example-supervisor depends on click (<8.2.0)
1: fact: example-supervisor depends on example-worker (>=0.1.0,<0.2.0)
1: fact: example-supervisor depends on pytest (^8.3.5)
1: fact: example-supervisor depends on pytest-testinfra (^10.2.2)
1: fact: example-supervisor depends on pyro5 (^5.15)
1: fact: example-supervisor depends on trio (^0.30.0)
1: fact: example-supervisor depends on neo-sockpuppet (^0.2.0)
1: selecting example-supervisor (0.2.0)
1: derived: neo-sockpuppet (>=0.2.0,<0.3.0)
1: derived: trio (>=0.30.0,<0.31.0)
1: derived: pyro5 (>=5.15,<6.0)
1: derived: pytest-testinfra (>=10.2.2,<11.0.0)
1: derived: pytest (>=8.3.5,<9.0.0)
1: derived: example-worker (>=0.1.0,<0.2.0)
1: derived: click (<8.2.0)
1: derived: fastapi[standard] (>=0.115.12,<0.116.0)
Source (PyPI): Getting info for neo-sockpuppet (0.2.0) from PyPI
Creating new session for pypi.org
[urllib3:urllib3.connectionpool] Starting new HTTPS connection (1): pypi.org:443
[urllib3:urllib3.connectionpool] https://pypi.org:443 "GET /pypi/neo-sockpuppet/0.2.0/json HTTP/1.1" 404 24
1: fact: neo-sockpuppet (0.2.0) depends on anycorn (>=0.18.1,<0.19.0)
1: fact: neo-sockpuppet (0.2.0) depends on anyio (>=4.9.0,<5.0.0)
1: fact: neo-sockpuppet (0.2.0) depends on pyro5 (>=5.15,<6.0)
1: selecting neo-sockpuppet (0.2.0)
1: derived: anyio (>=4.9.0,<5.0.0)
1: derived: anycorn (>=0.18.1,<0.19.0)
1: fact: anycorn (0.18.1) depends on anyio (>=4.0,<5.0)
1: fact: anycorn (0.18.1) depends on exceptiongroup (>=1.1.0,<2.0)
1: fact: anycorn (0.18.1) depends on h11 (*)
1: fact: anycorn (0.18.1) depends on h2 (>=3.1.0)
1: fact: anycorn (0.18.1) depends on hpack (*)
1: fact: anycorn (0.18.1) depends on priority (*)
1: fact: anycorn (0.18.1) depends on rich-click (>=1.8.3,<2.0.0)
1: fact: anycorn (0.18.1) depends on tomli (*)
1: fact: anycorn (0.18.1) depends on typing-extensions (*)
1: fact: anycorn (0.18.1) depends on wsproto (>=0.14.0)
1: selecting anycorn (0.18.1)
1: derived: wsproto (>=0.14.0)
1: derived: typing-extensions
1: derived: tomli
1: derived: rich-click (>=1.8.3,<2.0.0)
1: derived: priority
1: derived: hpack
1: derived: h2 (>=3.1.0)
1: derived: h11
1: derived: exceptiongroup (>=1.1.0,<2.0)
Source (PyPI): Getting info for example-worker (0.1.0) from PyPI
[urllib3:urllib3.connectionpool] https://pypi.org:443 "GET /pypi/example-worker/0.1.0/json HTTP/1.1" 404 24
1: fact: example-worker (0.1.0) depends on click (<8.2.0)
1: fact: example-worker (0.1.0) depends on fastapi[standard] (>=0.115.12,<0.116.0)
1: selecting example-worker (0.1.0)
1: fact: fastapi[standard] (0.115.12) depends on fastapi (0.115.12)
1: fact: fastapi[standard] (0.115.12) depends on starlette (>=0.40.0,<0.47.0)
1: fact: fastapi[standard] (0.115.12) depends on pydantic (>=1.7.4,<1.8 || >1.8,<1.8.1 || >1.8.1,<2.0.0 || >2.0.0,<2.0.1 || >2.0.1,<2.1.0 || >2.1.0,<3.0.0)
1: fact: fastapi[standard] (0.115.12) depends on typing-extensions (>=4.8.0)
1: fact: fastapi[standard] (0.115.12) depends on fastapi-cli[standard] (>=0.0.5)
1: fact: fastapi[standard] (0.115.12) depends on httpx (>=0.23.0)
1: fact: fastapi[standard] (0.115.12) depends on jinja2 (>=3.1.5)
1: fact: fastapi[standard] (0.115.12) depends on python-multipart (>=0.0.18)
1: fact: fastapi[standard] (0.115.12) depends on email-validator (>=2.0.0)
1: fact: fastapi[standard] (0.115.12) depends on uvicorn[standard] (>=0.12.0)
1: selecting fastapi[standard] (0.115.12)
1: derived: uvicorn[standard] (>=0.12.0)
1: derived: email-validator (>=2.0.0)
1: derived: python-multipart (>=0.0.18)
1: derived: jinja2 (>=3.1.5)
1: derived: httpx (>=0.23.0)
1: derived: fastapi-cli[standard] (>=0.0.5)
1: derived: typing-extensions (>=4.8.0)
1: derived: pydantic (>=1.7.4,!=1.8,!=1.8.1,!=2.0.0,!=2.0.1,!=2.1.0,<3.0.0)
1: derived: starlette (>=0.40.0,<0.47.0)
1: derived: fastapi (==0.115.12)
1: fact: h2 (4.2.0) depends on hyperframe (>=6.1,<7)
1: fact: h2 (4.2.0) depends on hpack (>=4.1,<5)
1: selecting h2 (4.2.0)
1: derived: hpack (>=4.1,<5)
1: derived: hyperframe (>=6.1,<7)
1: fact: fastapi (0.115.12) depends on starlette (>=0.40.0,<0.47.0)
1: fact: fastapi (0.115.12) depends on pydantic (>=1.7.4,<1.8 || >1.8,<1.8.1 || >1.8.1,<2.0.0 || >2.0.0,<2.0.1 || >2.0.1,<2.1.0 || >2.1.0,<3.0.0)
1: fact: fastapi (0.115.12) depends on typing-extensions (>=4.8.0)
1: selecting fastapi (0.115.12)
1: fact: pytest (8.3.5) depends on colorama (*)
1: fact: pytest (8.3.5) depends on exceptiongroup (>=1.0.0rc8)
1: fact: pytest (8.3.5) depends on iniconfig (*)
1: fact: pytest (8.3.5) depends on packaging (*)
1: fact: pytest (8.3.5) depends on pluggy (>=1.5,<2)
1: fact: pytest (8.3.5) depends on tomli (>=1)
1: selecting pytest (8.3.5)
1: derived: tomli (>=1)
1: derived: pluggy (>=1.5,<2)
1: derived: packaging
1: derived: iniconfig
1: derived: colorama
1: fact: wsproto (1.2.0) depends on h11 (>=0.9.0,<1)
1: selecting wsproto (1.2.0)
1: derived: h11 (>=0.9.0,<1)
1: fact: httpx (0.28.1) depends on anyio (*)
1: fact: httpx (0.28.1) depends on certifi (*)
1: fact: httpx (0.28.1) depends on httpcore (==1.*)
1: fact: httpx (0.28.1) depends on idna (*)
1: selecting httpx (0.28.1)
1: derived: idna
1: derived: httpcore (==1.*)
1: derived: certifi
1: fact: pydantic (2.11.4) depends on annotated-types (>=0.6.0)
1: fact: pydantic (2.11.4) depends on pydantic-core (2.33.2)
1: fact: pydantic (2.11.4) depends on typing-extensions (>=4.12.2)
1: fact: pydantic (2.11.4) depends on typing-inspection (>=0.4.0)
1: selecting pydantic (2.11.4)
1: derived: typing-inspection (>=0.4.0)
1: derived: typing-extensions (>=4.12.2)
1: derived: pydantic-core (==2.33.2)
1: derived: annotated-types (>=0.6.0)
1: fact: starlette (0.46.2) depends on anyio (>=3.6.2,<5)
1: selecting starlette (0.46.2)
1: fact: trio (0.30.0) depends on attrs (>=23.2.0)
1: fact: trio (0.30.0) depends on sortedcontainers (*)
1: fact: trio (0.30.0) depends on idna (*)
1: fact: trio (0.30.0) depends on outcome (*)
1: fact: trio (0.30.0) depends on sniffio (>=1.3.0)
1: fact: trio (0.30.0) depends on cffi (>=1.14)
1: fact: trio (0.30.0) depends on exceptiongroup (*)
1: selecting trio (0.30.0)
1: derived: cffi (>=1.14)
1: derived: sniffio (>=1.3.0)
1: derived: outcome
1: derived: sortedcontainers
1: derived: attrs (>=23.2.0)
1: fact: pyro5 (5.15) depends on serpent (>=1.41)
1: selecting pyro5 (5.15)
1: derived: serpent (>=1.41)
1: fact: pytest-testinfra (10.2.2) depends on pytest (>=6)
1: selecting pytest-testinfra (10.2.2)
1: fact: click (8.1.8) depends on colorama (*)
1: selecting click (8.1.8)
1: derived: colorama
1: fact: anyio (4.9.0) depends on exceptiongroup (>=1.0.2)
1: fact: anyio (4.9.0) depends on idna (>=2.8)
1: fact: anyio (4.9.0) depends on sniffio (>=1.1)
1: fact: anyio (4.9.0) depends on typing_extensions (>=4.5)
1: selecting anyio (4.9.0)
1: derived: typing_extensions (>=4.5)
1: derived: idna (>=2.8)
1: fact: rich-click (1.8.9) depends on click (>=7)
1: fact: rich-click (1.8.9) depends on rich (>=10.7)
1: fact: rich-click (1.8.9) depends on typing_extensions (>=4)
1: selecting rich-click (1.8.9)
1: derived: rich (>=10.7)
1: fact: rich (14.0.0) depends on typing-extensions (>=4.0.0,<5.0)
1: fact: rich (14.0.0) depends on pygments (>=2.13.0,<3.0.0)
1: fact: rich (14.0.0) depends on markdown-it-py (>=2.2.0)
1: selecting rich (14.0.0)
1: derived: markdown-it-py (>=2.2.0)
1: derived: pygments (>=2.13.0,<3.0.0)
1: derived: typing-extensions (>=4.0.0,<5.0)
1: fact: markdown-it-py (3.0.0) depends on mdurl (>=0.1,<1.0)
1: selecting markdown-it-py (3.0.0)
1: derived: mdurl (>=0.1,<1.0)
1: fact: exceptiongroup (1.3.0) depends on typing-extensions (>=4.6.0)
1: selecting exceptiongroup (1.3.0)
1: derived: typing-extensions (>=4.6.0)
1: fact: uvicorn[standard] (0.34.2) depends on uvicorn (0.34.2)
1: fact: uvicorn[standard] (0.34.2) depends on click (>=7.0)
1: fact: uvicorn[standard] (0.34.2) depends on h11 (>=0.8)
1: fact: uvicorn[standard] (0.34.2) depends on typing-extensions (>=4.0)
1: fact: uvicorn[standard] (0.34.2) depends on colorama (>=0.4)
1: fact: uvicorn[standard] (0.34.2) depends on httptools (>=0.6.3)
1: fact: uvicorn[standard] (0.34.2) depends on python-dotenv (>=0.13)
1: fact: uvicorn[standard] (0.34.2) depends on pyyaml (>=5.1)
1: fact: uvicorn[standard] (0.34.2) depends on uvloop (>=0.14.0,<0.15.0 || >0.15.0,<0.15.1 || >0.15.1)
1: fact: uvicorn[standard] (0.34.2) depends on watchfiles (>=0.13)
1: fact: uvicorn[standard] (0.34.2) depends on websockets (>=10.4)
1: selecting uvicorn[standard] (0.34.2)
1: derived: websockets (>=10.4)
1: derived: watchfiles (>=0.13)
1: derived: uvloop (>=0.14.0,!=0.15.0,!=0.15.1)
1: derived: pyyaml (>=5.1)
1: derived: python-dotenv (>=0.13)
1: derived: httptools (>=0.6.3)
1: derived: colorama (>=0.4)
1: derived: typing-extensions (>=4.0)
1: derived: uvicorn (==0.34.2)
1: fact: email-validator (2.2.0) depends on dnspython (>=2.0.0)
1: fact: email-validator (2.2.0) depends on idna (>=2.0.0)
1: selecting email-validator (2.2.0)
1: derived: dnspython (>=2.0.0)
1: fact: jinja2 (3.1.6) depends on MarkupSafe (>=2.0)
1: selecting jinja2 (3.1.6)
1: derived: MarkupSafe (>=2.0)
0: Duplicate dependencies for uvicorn
0: Merging requirements for uvicorn
1: fact: fastapi-cli[standard] (0.0.7) depends on fastapi-cli (0.0.7)
1: fact: fastapi-cli[standard] (0.0.7) depends on typer (>=0.12.3)
1: fact: fastapi-cli[standard] (0.0.7) depends on uvicorn[standard] (>=0.15.0)
1: fact: fastapi-cli[standard] (0.0.7) depends on rich-toolkit (>=0.11.1)
1: selecting fastapi-cli[standard] (0.0.7)
1: derived: rich-toolkit (>=0.11.1)
1: derived: uvicorn[standard] (>=0.15.0)
1: derived: typer (>=0.12.3)
1: derived: fastapi-cli (==0.0.7)
1: fact: httpcore (1.0.9) depends on certifi (*)
1: fact: httpcore (1.0.9) depends on h11 (>=0.16)
1: selecting httpcore (1.0.9)
1: derived: h11 (>=0.16)
1: fact: typing-inspection (0.4.1) depends on typing-extensions (>=4.12.0)
1: selecting typing-inspection (0.4.1)
1: fact: pydantic-core (2.33.2) depends on typing-extensions (>=4.6.0,<4.7.0 || >4.7.0)
1: selecting pydantic-core (2.33.2)
1: fact: cffi (1.17.1) depends on pycparser (*)
1: selecting cffi (1.17.1)
1: derived: pycparser
1: fact: outcome (1.3.0.post0) depends on attrs (>=19.2.0)
1: selecting outcome (1.3.0.post0)
1: fact: watchfiles (1.0.5) depends on anyio (>=3.0.0)
1: selecting watchfiles (1.0.5)
1: fact: uvicorn (0.34.2) depends on click (>=7.0)
1: fact: uvicorn (0.34.2) depends on h11 (>=0.8)
1: fact: uvicorn (0.34.2) depends on typing-extensions (>=4.0)
1: selecting uvicorn (0.34.2)
1: derived: typing-extensions (>=4.0)
1: fact: rich-toolkit (0.14.6) depends on click (>=8.1.7)
1: fact: rich-toolkit (0.14.6) depends on rich (>=13.7.1)
1: fact: rich-toolkit (0.14.6) depends on typing-extensions (>=4.12.2)
1: selecting rich-toolkit (0.14.6)
1: fact: typer (0.15.3) depends on click (>=8.0.0)
1: fact: typer (0.15.3) depends on typing-extensions (>=3.7.4.3)
1: fact: typer (0.15.3) depends on shellingham (>=1.3.0)
1: fact: typer (0.15.3) depends on rich (>=10.11.0)
1: selecting typer (0.15.3)
1: derived: shellingham (>=1.3.0)
1: fact: fastapi-cli (0.0.7) depends on typer (>=0.12.3)
1: fact: fastapi-cli (0.0.7) depends on uvicorn[standard] (>=0.15.0)
1: fact: fastapi-cli (0.0.7) depends on rich-toolkit (>=0.11.1)
1: selecting fastapi-cli (0.0.7)
1: selecting typing-extensions (4.13.2)
1: selecting tomli (2.2.1)
1: selecting priority (2.0.0)
1: selecting hpack (4.1.0)
1: selecting h11 (0.16.0)
1: selecting python-multipart (0.0.20)
1: selecting hyperframe (6.1.0)
1: selecting pluggy (1.6.0)
1: selecting packaging (25.0)
1: selecting iniconfig (2.1.0)
1: selecting colorama (0.4.6)
1: selecting idna (3.10)
1: selecting certifi (2025.4.26)
1: selecting annotated-types (0.7.0)
1: selecting sniffio (1.3.1)
1: selecting sortedcontainers (2.4.0)
1: selecting attrs (25.3.0)
1: selecting serpent (1.41)
1: selecting pygments (2.19.1)
1: selecting mdurl (0.1.2)
1: selecting websockets (15.0.1)
1: selecting uvloop (0.21.0)
1: selecting pyyaml (6.0.2)
1: selecting python-dotenv (1.1.0)
1: selecting httptools (0.6.4)
1: selecting dnspython (2.7.0)
1: selecting markupsafe (3.0.2)
1: selecting pycparser (2.22)
1: selecting shellingham (1.5.4)
1: Version solving took 0.293 seconds.
1: Tried 1 solutions.
Finding the necessary packages for the current system
No dependencies to install or update
Per the docs
Note that this will not update versions for dependencies outside their version constraints specified in the pyproject.toml file. In other terms, poetry update foo will be a no-op if the version constraint specified for foo is ~2.3 or 2.3 and 2.4 is available. In order for foo to be updated, you must update the constraint, for example ^2.3. You can do this using the add command
Why not use poetry add? Why would it be an improvement for poetry update to do what poetry add already does?
@dimbleby: mostly because I would expect the command called update to allow me to update the dependencies :) And specifically, there needs to be a way to tell it to update the resolution to a specific version (i.e. what gets written to poetry.lock), independent of the project constraints that add manages. This is useful for all kinds of scenarios, including workaround for broken upstream releases, testing, etc. These are not super frequent needs individually, but they're frequent enough, and critical when you need them.
the way to direct the resolution to a particular solution is to update the constraints in pyproject.toml (eg but not necessarily through poetry add). I do not think it is likely that your proposed side-channel will be implemented.
@dimbleby: but there's a difference between dependency constraints (which are contained by pyproject.toml and mainly controlled by poetry add), and the concrete dependency resolution (which is contained by poetry.lock and controlled by poetry update). That is a pretty clear and unambiguous model, but if messing with the constraints is the only way to influence the resolution, that contradicts the basic concepts of the model in a pretty severe way. Not having any way to control the resolution and instead having it drift arbirtarily from run to run of poetry update, based purely on what happens to be in the index at the time, with no way for the user to exert influence on it, also feels very counter to the idea that the dependency resolution should be the tool for the user to achieve a stable, predictable state of the environment.
Also, regardless of the above, poetry update will accept utter nonsense as arguments without so much as a peep, which is very clearly a bug.
If messing with the constraints is the only way to influence the resolution, that contradicts the basic concepts of the model in a pretty severe way
It does not.
Also, regardless of the above ...
it was you who chose to try and squeeze two completely separate conversations into one issue report ;-)