Skip to content

version() fails on anyio >= 3: cancelled_caughtshould becancel_called` #1520

Description

@goldnews

Bug Report: jupyterlab-git 0.54.1 Fails to Detect Git Due to anyio API Incompatibility

Summary

jupyterlab_git_core/git.py uses the deprecated attribute scope.cancelled_caught, which was removed in anyio 3. This causes every call to the version() method (and potentially other methods using __execute()) to raise an AttributeError, silently returning None. The frontend then displays:

"git command not found - please ensure you have Git > 2 installed"
(or localized: "git 命令未找到 - 请确保您已安装 Git 2 或更高版本")

even though Git is correctly installed and available in the system PATH.

Root Cause

In jupyterlab_git_core/git.py, line 268, the attribute scope.cancelled_caught is used:

# git.py, line 268 — current code (BROKEN)
with anyio.move_on_after(self._execute_timeout) as scope:
    await lock.acquire()
if scope.cancelled_caught:   # <-- renamed in anyio 3
    return 1, "", "Unable to get the lock on the directory"

In anyio 1.x / 2.x, the attribute was named cancelled_caught. Starting from anyio 3.x, it was renamed to cancel_called.

However, jupyterlab-git-core does not pin an anyio version constraint that prevents installing anyio >= 3. The package metadata only specifies:

anyio

without any upper bound. As a result, any environment with anyio >= 3 (released in 2021) is affected.

The error propagates as follows:

  1. Git.version() calls self.__execute(["git", "--version"], cwd=os.curdir) (git.py:1999)
  2. __execute() reaches line 268 and tries scope.cancelled_caughtAttributeError
  3. The exception propagates up through version() unhandled
  4. GitSettingsHandler.get() catches the exception and silently sets gitVersion = None (handlers.py:848-850)
  5. The /git/settings API returns {"gitVersion": null, ...}
  6. The frontend sees null and displays the "git command not found" error

Minimal Reproduction

import asyncio
from jupyterlab_git_core.git import Git

async def main():
    g = Git()
    version = await g.version()
    print(version)  # Expected: "2.33.0", Actual: AttributeError

asyncio.run(main())

Error:

AttributeError: 'CancelScope' object has no attribute 'cancelled_caught'

Affected Versions

Component Version
jupyterlab-git 0.54.1
jupyterlab-git-core 0.54.1
anyio >= 3.0

Fix

Change scope.cancelled_caught to scope.cancel_called in jupyterlab_git_core/git.py line 268:

- if scope.cancelled_caught:
+ if scope.cancel_called:

Recommended Upstream Fix

  1. Apply the one-line fix above (rename cancelled_caughtcancel_called)
  2. Add a version constraint for anyio in the package metadata to prevent future regressions:
    anyio >= 3.0
    

Environment Details

Item Value
OS macOS Darwin 25.5.0
Python 3.10.13
jupyterlab 4.6.2
jupyter-server 2.20.0
jupyterlab-git 0.54.1
jupyterlab-git-core 0.54.1
anyio 3.5.0
git 2.33.0 (via Homebrew)
Shell zsh (launched from terminal)

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions