Skip to content

Struggling to setup java in pyimagej _guess_java_version (but not scyjava) #337

@tlambert03

Description

@tlambert03

I'm trying to run pyimagej tests locally, and I'm having a hard time setting up Java. I thought it might be useful for you to see my full thought process, so here goes:

clone pyimagej, cd, and uv sync

dev/self/pyimagej on  main [!]
➜ uv sync
Using CPython 3.13.2
Creating virtual environment at: .venv
Resolved 197 packages in 261ms
Installed 106 packages in 288ms
 + alabaster==1.0.0
 + appnope==0.1.4
 + asttokens==3.0.0
 + attrs==25.3.0
 + babel==2.17.0
 + build==1.3.0
 + certifi==2025.8.3
 + cfgv==3.4.0
 + charset-normalizer==3.4.3
 + cjdk==0.4.1
 + click==8.2.1
 + comm==0.2.3
 + debugpy==1.8.16
 + decorator==5.2.1
 + distlib==0.4.0
 + docutils==0.21.2
 + entrypoints==0.4
 + executing==2.2.0
 + fastjsonschema==2.21.2
 + filelock==3.19.1
 + identify==2.6.13
 + idna==3.10
 + imagesize==1.4.1
 + imglyb==2.1.0
 + importlib-metadata==8.7.0
 + iniconfig==2.1.0
 + ipykernel==6.29.5
 + ipython==9.4.0
 + ipython-pygments-lexers==1.1.1
 + jedi==0.19.2
 + jgo==1.0.6
 + jinja2==3.1.6
 + jpype1==1.6.0
 + jsonschema==4.25.1
 + jsonschema-specifications==2025.4.1
 + jupyter-cache==1.0.1
 + jupyter-client==7.4.9
 + jupyter-core==5.8.1
 + labeling==0.1.14
 + markdown-it-py==3.0.0
 + markupsafe==3.0.2
 + matplotlib-inline==0.1.7
 + mdit-py-plugins==0.5.0
 + mdurl==0.1.2
 + myst-nb==1.3.0
 + myst-parser==4.0.1
 + nbclient==0.10.2
 + nbformat==5.10.4
 + nest-asyncio==1.6.0
 + nodeenv==1.9.1
 + numpy==2.3.2
 + packaging==25.0
 + pandas==2.3.2
 + parso==0.8.5
 + pexpect==4.9.0
 + pillow==11.3.0
 + platformdirs==4.4.0
 + pluggy==1.6.0
 + pre-commit==4.3.0
 + progressbar2==4.5.0
 + prompt-toolkit==3.0.52
 + psutil==7.0.0
 + ptyprocess==0.7.0
 + pure-eval==0.2.3
 + pygments==2.19.2
 + pyimagej==1.7.1.dev0 (from file:///Users/talley/dev/self/pyimagej)
 + pyproject-hooks==1.2.0
 + pytest==8.4.1
 + python-dateutil==2.9.0.post0
 + python-utils==3.9.1
 + pytz==2025.2
 + pyyaml==6.0.2
 + pyzmq==27.0.2
 + referencing==0.36.2
 + requests==2.32.5
 + roman-numerals-py==3.1.0
 + rpds-py==0.27.1
 + ruff==0.12.11
 + scipy==1.16.1
 + scyjava==1.12.1
 + six==1.17.0
 + snowballstemmer==3.0.1
 + sphinx==8.2.3
 + sphinx-rtd-theme==3.0.2
 + sphinxcontrib-applehelp==2.0.0
 + sphinxcontrib-devhelp==2.0.0
 + sphinxcontrib-htmlhelp==2.1.0
 + sphinxcontrib-jquery==4.1
 + sphinxcontrib-jsmath==1.0.1
 + sphinxcontrib-qthelp==2.0.0
 + sphinxcontrib-serializinghtml==2.0.0
 + sqlalchemy==2.0.43
 + stack-data==0.6.3
 + tabulate==0.9.0
 + tifffile==2025.8.28
 + tornado==6.5.2
 + traitlets==5.14.3
 + trove-classifiers==2025.8.26.11
 + typing-extensions==4.15.0
 + tzdata==2025.2
 + urllib3==2.5.0
 + validate-pyproject==0.24.1
 + virtualenv==20.34.0
 + wcwidth==0.2.13
 + xarray==2025.8.0
 + zipp==3.23.0
dev/self/pyimagej on  main [!]
➜ source .venv/bin/activate

To begin with, i intentionally had no Java setup (no JAVA_HOME, etc..) and wanted to see the error:

dev/self/pyimagej on  main [!] via 🐍 3.13.2 via pyimagej
➜ java -version
The operation couldn’t be completed. Unable to locate a Java Runtime.
Please visit http://www.java.com for information on installing Java.

dev/self/pyimagej on  main [!] via 🐍 3.13.2 via pyimagej took 3.7s
➜ pytest -x
========================================================= test session starts ==========================================================
platform darwin -- Python 3.13.2, pytest-8.4.1, pluggy-1.6.0
rootdir: /Users/talley/dev/self/pyimagej
configfile: pyproject.toml
testpaths: tests
collected 87 items

tests/test_callbacks.py E

================================================================ ERRORS ================================================================
______________________________________________ ERROR at setup of test_when_imagej_starts _______________________________________________

request = <SubRequest 'ij' for <Function test_when_imagej_starts>>

conftest.py:65:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
src/imagej/__init__.py:1399: in init
    success = _create_jvm(ij_dir_or_version_or_endpoint, mode, add_legacy)
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
src/imagej/__init__.py:1542: in _create_jvm
    needs_unlock = _prepare_to_unlock_modules()
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
src/imagej/__init__.py:1797: in _prepare_to_unlock_modules
    major_version = _guess_java_version()
                    ^^^^^^^^^^^^^^^^^^^^^
src/imagej/__init__.py:1712: in _guess_java_version
    version_digits = sj.jvm_version()
                     ^^^^^^^^^^^^^^^^
.venv/lib/python3.13/site-packages/scyjava/_jvm.py:70: in jvm_version
    default_jvm_path = jpype.getDefaultJVMPath()
                       ^^^^^^^^^^^^^^^^^^^^^^^^^
.venv/lib/python3.13/site-packages/jpype/_jvmfinder.py:70: in getDefaultJVMPath
    return finder.get_jvm_path()
           ^^^^^^^^^^^^^^^^^^^^^
.venv/lib/python3.13/site-packages/jpype/_jvmfinder.py:184: in get_jvm_path
    jvm = method()
          ^^^^^^^^
.venv/lib/python3.13/site-packages/jpype/_jvmfinder.py:311: in _javahome_binary
    return subprocess.check_output(
../../../.local/share/uv/python/cpython-3.13.2-macos-aarch64-none/lib/python3.13/subprocess.py:474: in check_output
    return run(*popenargs, stdout=PIPE, timeout=timeout, check=True,
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

input = None, capture_output = False, timeout = None, check = True, popenargs = (['/usr/libexec/java_home'],), kwargs = {'stdout': -1}
process = <Popen: returncode: 1 args: ['/usr/libexec/java_home']>, stdout = b'', stderr = None, retcode = 1

    def run(*popenargs,
            input=None, capture_output=False, timeout=None, check=False, **kwargs):
        if input is not None:
            if kwargs.get('stdin') is not None:
                raise ValueError('stdin and input arguments may not both be used.')
            kwargs['stdin'] = PIPE

        if capture_output:
            if kwargs.get('stdout') is not None or kwargs.get('stderr') is not None:
                raise ValueError('stdout and stderr arguments may not be used '
                                 'with capture_output.')
            kwargs['stdout'] = PIPE
            kwargs['stderr'] = PIPE

        with Popen(*popenargs, **kwargs) as process:
            try:
                stdout, stderr = process.communicate(input, timeout=timeout)
            except TimeoutExpired as exc:
                process.kill()
                if _mswindows:
                    # Windows accumulates the output in a single blocking
                    # read() call run on child threads, with the timeout
                    # being done in a join() on those threads.  communicate()
                    # _after_ kill() is required to collect that and add it
                    # to the exception.
                    exc.stdout, exc.stderr = process.communicate()
                else:
                    # POSIX _communicate already populated the output so
                    # far into the TimeoutExpired exception.
                    process.wait()
                raise
            except:  # Including KeyboardInterrupt, communicate handled that.
                process.kill()
                # We don't call process.wait() as .__exit__ does that for us.
                raise
            retcode = process.poll()
            if check and retcode:
>               raise CalledProcessError(retcode, process.args,
                                         output=stdout, stderr=stderr)
E               subprocess.CalledProcessError: Command '['/usr/libexec/java_home']' returned non-zero exit status 1.

../../../.local/share/uv/python/cpython-3.13.2-macos-aarch64-none/lib/python3.13/subprocess.py:579: CalledProcessError
======================================================= short test summary info ========================================================
ERROR tests/test_callbacks.py::test_when_imagej_starts - subprocess.CalledProcessError: Command '['/usr/libexec/java_home']' returned non-zero exit status 1.
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
=========================================================== 1 error in 0.15s ===========================================================

So far as expected ... i then install openjdk 11 from homebrew

dev/self/pyimagej on  main [!] via 🐍 3.13.2 via pyimagej
➜ brew install openjdk@11
==> Downloading https://formulae.brew.sh/api/formula.jws.json
==> Downloading https://formulae.brew.sh/api/cask.jws.json
==> Fetching downloads for: openjdk@11
==> Downloading https://ghcr.io/v2/homebrew/core/openjdk/11/manifests/11.0.28
Already downloaded: /Users/talley/Library/Caches/Homebrew/downloads/855108ba8fb23b32ca4fe64a632e32e64a67cdc927c6ba12a9cc593967cdf2bc--openjdk@11-11.0.28.bottle_manifest.json
==> Fetching openjdk@11
==> Downloading https://ghcr.io/v2/homebrew/core/openjdk/11/blobs/sha256:c2f2b74da21a9062e4b288dedc5a0041814addbde1829b3113ef2d68e82821c
Already downloaded: /Users/talley/Library/Caches/Homebrew/downloads/a4be120bf53ec8523fd3634eb727a69099494743a45e868e777e36916f97f40b--openjdk@11--11.0.28.arm64_sequoia.bottle.tar.gz
==> Pouring openjdk@11--11.0.28.arm64_sequoia.bottle.tar.gz
==> Caveats
For the system Java wrappers to find this JDK, symlink it with
  sudo ln -sfn /opt/homebrew/opt/openjdk@11/libexec/openjdk.jdk /Library/Java/JavaVirtualMachines/openjdk-11.jdk

openjdk@11 is keg-only, which means it was not symlinked into /opt/homebrew,
because this is an alternate version of another formula.

If you need to have openjdk@11 first in your PATH, run:
  echo 'export PATH="/opt/homebrew/opt/openjdk@11/bin:$PATH"' >> ~/.zshrc

For compilers to find openjdk@11 you may need to set:
  export CPPFLAGS="-I/opt/homebrew/opt/openjdk@11/include"
==> Summary
🍺  /opt/homebrew/Cellar/openjdk@11/11.0.28: 667 files, 296.1MB
==> Running `brew cleanup openjdk@11`...
Disable this behaviour by setting `HOMEBREW_NO_INSTALL_CLEANUP=1`.
Hide these hints with `HOMEBREW_NO_ENV_HINTS=1` (see `man brew`).
==> No outdated dependents to upgrade!

and follow the instructions for system Java wrappers to find it:

dev/self/pyimagej on  main [!] via 🐍 3.13.2 via pyimagej took 3.5s
➜ sudo ln -sfn /opt/homebrew/opt/openjdk@11/libexec/openjdk.jdk /Library/Java/JavaVirtualMachines/openjdk-11.jdk

dev/self/pyimagej on  main [!] via 🐍 3.13.2 via pyimagej
➜ java -version
openjdk version "11.0.28" 2025-07-15
OpenJDK Runtime Environment Homebrew (build 11.0.28+0)
OpenJDK 64-Bit Server VM Homebrew (build 11.0.28+0, mixed mode)

great! let's test again:

dev/self/pyimagej on  main [!] via 🐍 3.13.2 via pyimagej
➜ pytest -x
========================================================= test session starts ==========================================================
platform darwin -- Python 3.13.2, pytest-8.4.1, pluggy-1.6.0
rootdir: /Users/talley/dev/self/pyimagej
configfile: pyproject.toml
testpaths: tests
collected 87 items

tests/test_callbacks.py E

================================================================ ERRORS ================================================================
______________________________________________ ERROR at setup of test_when_imagej_starts _______________________________________________

request = <SubRequest 'ij' for <Function test_when_imagej_starts>>

conftest.py:65:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
src/imagej/__init__.py:1399: in init
    success = _create_jvm(ij_dir_or_version_or_endpoint, mode, add_legacy)
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
src/imagej/__init__.py:1542: in _create_jvm
    needs_unlock = _prepare_to_unlock_modules()
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
src/imagej/__init__.py:1797: in _prepare_to_unlock_modules
    major_version = _guess_java_version()
                    ^^^^^^^^^^^^^^^^^^^^^
src/imagej/__init__.py:1712: in _guess_java_version
    version_digits = sj.jvm_version()
                     ^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

    def jvm_version() -> tuple[int, ...]:
        ...
        if java is None:
>           raise RuntimeError(f"No java executable found inside: {p}")
E           RuntimeError: No java executable found inside: /opt/homebrew/Cellar/openjdk@11/11.0.28/libexec/openjdk.jdk

hmm, weird:

dev/self/pyimagej on  main [!] via 🐍 3.13.2 via pyimagej
➜ ls /opt/homebrew/Cellar/openjdk@11/11.0.28
bin  include  INSTALL_RECEIPT.json  libexec  LICENSE  README.md  sbom.spdx.json  share

let uninstall the brew version and try cdjk instead:

dev/self/pyimagej on  main [!] via 🐍 3.13.2 via pyimagej
➜ brew uninstall openjdk@11
Uninstalling /opt/homebrew/Cellar/openjdk@11/11.0.28... (667 files, 296.1MB)

dev/self/pyimagej on  main [!] via 🐍 3.13.2 via pyimagej
➜ java -version
The operation couldn’t be completed. Unable to locate a Java Runtime.

dev/self/pyimagej on  main [!] via 🐍 3.13.2 via pyimagej
➜ sudo rm -rf /Library/Java/JavaVirtualMachines/openjdk-11.jdk

dev/self/pyimagej on  main [!] via 🐍 3.13.2 via pyimagej took 3.5s
➜ cjdk ls
adoptium:1.24.0.2
temurin:1.24.0.2
zulu:11.0.28
zulu-jre:8.0.452
zulu-jre:11.0.27

dev/self/pyimagej on  main [!] via 🐍 3.13.2 via pyimagej
➜ cjdk -j zulu:11 java-home
/Users/talley/Library/Caches/cjdk/v0/jdks/6401447c002c49115b1670dd36881be09a724a66/zulu11.82.19-ca-jdk11.0.28-macosx_aarch64

dev/self/pyimagej on  main [!] via 🐍 3.13.2 via pyimagej
➜ export JAVA_HOME=$(cjdk -j zulu:11 java-home)

dev/self/pyimagej on  main [!] via 🐍 3.13.2 via pyimagej
➜ java -version
openjdk version "11.0.28" 2025-07-15 LTS
OpenJDK Runtime Environment Zulu11.82+19-CA (build 11.0.28+6-LTS)
OpenJDK 64-Bit Server VM Zulu11.82+19-CA (build 11.0.28+6-LTS, mixed mode)

alas, still same error:

dev/self/pyimagej on  main [!] via 🐍 3.13.2 via pyimagej
➜ pytest -x
============================================================ test session starts =============================================================
platform darwin -- Python 3.13.2, pytest-8.4.1, pluggy-1.6.0
rootdir: /Users/talley/dev/self/pyimagej
configfile: pyproject.toml
testpaths: tests
collected 87 items

tests/test_callbacks.py E

=================================================================== ERRORS ===================================================================
_________________________________________________ ERROR at setup of test_when_imagej_starts __________________________________________________

request = <SubRequest 'ij' for <Function test_when_imagej_starts>>

conftest.py:65:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
src/imagej/__init__.py:1399: in init
    success = _create_jvm(ij_dir_or_version_or_endpoint, mode, add_legacy)
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
src/imagej/__init__.py:1542: in _create_jvm
    needs_unlock = _prepare_to_unlock_modules()
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
src/imagej/__init__.py:1797: in _prepare_to_unlock_modules
    major_version = _guess_java_version()
                    ^^^^^^^^^^^^^^^^^^^^^
src/imagej/__init__.py:1712: in _guess_java_version
    version_digits = sj.jvm_version()
                     ^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

    def jvm_version() -> tuple[int, ...]:
        ...
        if java is None:
>           raise RuntimeError(f"No java executable found inside: {p}")
E           RuntimeError: No java executable found inside: /Users/talley/Library/Caches/cjdk/v0/jdks/6401447c002c49115b1670dd36881be09a724a66/zulu11.82.19-ca-jdk11.0.28-macosx_aarch64/zulu-11.jdk

.venv/lib/python3.13/site-packages/scyjava/_jvm.py:94: RuntimeError

question: is this my error in setting up java? or an error in pyimagej _guess_java_version -> jvm_version?

edit: to be clear, I specifically don't want to use mamba/conda openjdk here.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions