Skip to content

[Bug]: ty [environment] does not work on generated venv for ty IDE extension #938

Description

@gkouretas-maven

What happened?

When trying to integrate with the ty VSCode/Cursor extension, I was unable to configure things in a way where a virtual environment could be linked in my ty.toml due to it erroring when resolving the home path.

2026-04-16 21:16:05.993043258 ERROR Failed to create project for workspace `file:///<>`: Failed to parse the `pyvenv.cfg` file at `/<>/bazel-out/<>/bin/.python3.venv/pyvenv.cfg` because the following error was encountered when trying to resolve the `home` value to a directory on disk: No such file or directory (os error 2). Falling back to default settings

I believe the issue was due to the inability of the extension (which I believe utilizes the base VSCode interpreter search, but haven't confirmed) to resolve the relative ./bin/ path from the virtual environment that is set from the pyvenv.cfg template:

home = ./bin/ # <- this
implementation = CPython
version_info = {{MAJOR}}.{{MINOR}}.{{PATCH}}
include-system-site-packages = {{INCLUDE_SYSTEM_SITE}}
aspect-include-user-site-packages = {{INCLUDE_USER_SITE}}
relocatable = true
{{INTERPRETER}}

Version

Development (host) and target OS/architectures: Linux ARM64

Output of bazel --version: bazel 9.0.0

Version of the Aspect rules, or other relevant rules from your
WORKSPACE or MODULE.bazel file:

  • rules_py -> 1.11.2
  • ty -> 0.0.9
  • VSCode/Cursor extension: astral-sh.ty@2026.36.0

Language(s) and/or frameworks involved:

How to reproduce

Create a simple ty.toml file

[src]
exclude = [
    "pytest_test",
    ".pytest_main"
]

[rules]
unresolved-import = "ignore"
[environment]
python = ".python3.venv"


BUILD rules to generate the a minimal virtual environment:

load("@aspect_rules_py//py:defs.bzl", "py_binary")
load("@bazel_skylib//rules:write_file.bzl", "write_file")

write_file(
    name = "dummy_script",
    out = "dummy_script.py",
    content = ["print('Hello, World!')"],
    is_executable = True,
    visibility = ["//visibility:private"],
)

py_binary(
    name = "python3",
    srcs = [":dummy_script"],
    visibility = ["//visibility:private"],
)


Execute to create the virtual environment:

bazel run //:python3.venv


VSCode/Cursor settings for the ty extension:

"ty.path": ["/path/to/ty"],
"ty.configurationFile": "/path/to/ty.toml",


In VSCode/Cursor query for the client logs:

> ty: Show client logs


An error message along these lines should appear (go to `Console > Output > ty Language Server`):

2026-04-16 21:16:05.993043258 ERROR Failed to create project for workspace `file:///<>`: Failed to parse the `pyvenv.cfg` file at `/<>/bazel-out/<>/bin/.python3.venv/pyvenv.cfg` because the following error was encountered when trying to resolve the `home` value to a directory on disk: No such file or directory (os error 2). Falling back to default settings

Any other information?

I was able to crudely patch things to make the path relative to the folder containing the virtual environment, rather than the virtual environment itself, which fixed the problem.

I don't have a great sense for if this would break other commonly used workflows, I assume you all would have some insight into this.

--- a/py/tools/py/src/pyvenv.cfg.tmpl
+++ b/py/tools/py/src/pyvenv.cfg.tmpl
@@ -1,4 +1,4 @@
-home = ./bin/
+home = {{HOME}}
 implementation = CPython
 version_info = {{MAJOR}}.{{MINOR}}.{{PATCH}}
 include-system-site-packages = {{INCLUDE_SYSTEM_SITE}}

--- a/py/tools/py/src/venv.rs
+++ b/py/tools/py/src/venv.rs
@@ -341,9 +341,12 @@ aspect-runfiles-repo = {1}
 
     // Create the `pyvenv.cfg` file
     // FIXME: Should this come from the ruleset?
+    // NOTE(george): this takes the last two components of the home directory to yield the output: `<venv>/bin`
+    let home_dir: PathBuf = venv.home_dir.components().rev().take(2).collect::<Vec<_>>().into_iter().collect();
     fs::write(
         &venv.home_dir.join("pyvenv.cfg"),
         include_str!("pyvenv.cfg.tmpl")
+            .replace("{{HOME}}", &home_dir.to_str().unwrap())
             .replace("{{MAJOR}}", &venv.version_info.major.to_string())
             .replace("{{MINOR}}", &venv.version_info.minor.to_string())
             .replace("{{PATCH}}", &venv.version_info.patch.to_string())

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions