Skip to content

fix(server): avoid runtime loads for passive location reads #44272

Closed

Description

@altendky

Description

Several read-only API endpoints currently run through LocationMiddleware or SessionLocationMiddleware, which always calls LocationServiceMap.get. For an unloaded Location, observing metadata or checking ephemeral state therefore constructs and retains the complete Location runtime, including filesystem search, watchers, plugins, MCP processes, catalogs, and VCS services.

An instrumented comparison demonstrated the amplification:

  • Polling pending Forms and Permissions for 18 historical Locations created 18 complete runtime graphs, 72,364 server inotify watches, and a 140-process tree.
  • With the polling client closed, no historical graphs were built; the server retained 14 watches and a 7-process tree.

The polling client should not have enumerated historical Locations, but passive reads should not prepare every workspace requested by an authenticated client.

The proposed invariant is:

  • Durable metadata reads use the database or lightweight Location/Project resolution without constructing a runtime.
  • Runtime-owned collection reads use an existing runtime and return an empty collection when none exists.
  • Runtime-owned item reads use an existing runtime and return their current not-found error when none exists.
  • An existing in-progress runtime build is joined and retained for the request scope.
  • Creation, execution, runtime-derived catalogs/configuration, and explicit preparation may continue to construct runtimes.

The affected metadata reads are:

location.get, project.current, project.list, permission.saved.list, and session.instructions.entry.list.

The affected existing-runtime reads are:

form.request.list, permission.request.list, session.form.list, session.form.get, session.form.state, session.permission.list, session.permission.get, pty.list, pty.get, shell.list, shell.get, and shell.output.

Existing-runtime reads require an atomic, scoped optional acquisition operation. Effect-TS/effect#7411 (released in 4.0.0-rc.112, we are using rc.111 right now) adds RcMap.getOption and LayerMap.contextEffectOption for this purpose. Missing entries return Option.none without building a layer, while ready or in-progress entries are retained for the caller scope.

OpenCode can wrap LayerMap.contextEffectOption as LocationServiceMap.useIfPresent. It should not compose RcMap.has and get, because TTL expiry or invalidation can remove an entry between those operations and cause get to construct a new runtime.

The optional existing-runtime portion of this fix depends on Effect PR #7411 being merged, released, and adopted by OpenCode.

Acceptance criteria:

  • Calling any affected endpoint for an unloaded Location does not add a LocationServiceMap entry.
  • Collection endpoints return their existing empty response shape when runtime state is absent.
  • Item endpoints preserve their current not-found response.
  • Missing Sessions still return SessionNotFoundError.
  • Existing and in-progress runtimes continue to expose their current state correctly.
  • The calls do not start filesystem search, watchers, plugins, MCP processes, catalogs, or VCS services.
  • Runtime-demanding endpoints retain their current behavior.

Filesystem/VCS capability decomposition, catalog/config semantics, runtime TTL policy, Integration attempts, mutations, and explicit prewarming are out of scope.

Plugins

@onshape-mcp/opencode-auth and local ~/.config/opencode/plugins/claude-plugin.js. The reproduction is at the authenticated HTTP API boundary and is not plugin-specific.

OpenCode version

Local V2 build opencode2 v0.0.0-v2-202608222007 from commit bdec7a4f87a6a29d37dee975716273a40cbc77a3.

Steps to reproduce

  1. Start a V2 server and identify a valid project directory that is absent from GET /api/debug/location.
  2. Call GET /api/permission/request or GET /api/form/request with that directory in location[directory].
  3. Call GET /api/debug/location again.
  4. Observe that the read added a complete Location runtime.
  5. Inspect the server's child processes and /proc/<pid>/fdinfo inotify counts.
  6. Repeat with several unloaded directories and observe one retained runtime, associated watchers, and child processes per directory.
  7. Compare with a run where those reads are not made.

The same behavior can be observed with the other listed routes by querying unloaded Locations or Sessions whose Location runtime is not active.

Screenshot and/or share link

No share link. This is server runtime behavior; the instrumented resource comparison is included above.

Operating System

Ubuntu Linux x86_64, kernel 7.0.0-29-generic.

Terminal

xterm-256color. The reproduction uses authenticated HTTP requests and is not terminal-specific.

Activity

  1. altendky commented on Aug 31, 2026

    @altendky
    ContributorAuthor

    Status update: #45994 addressed the primary resource-amplification scenario demonstrated here.

    Session-family hydration of pending forms and permissions now uses atomic optional acquisition for session.form.list and session.permission.list, returning an empty collection for an unloaded Location rather than constructing its runtime. The special global-form list path received the same treatment. This prevents polling historical sessions from creating the runtime graphs, watchers, plugins, MCP processes, and child-process growth described in the reproduction.

    The broader passive-read invariant and endpoint audit in this issue remain incomplete. In particular, the listed metadata reads, location-wide pending-request reads, individual form and permission reads, PTY reads, and shell reads have not all been converted to lightweight or existing-runtime-only acquisition.

    Accordingly, #45994 resolves the primary observed failure mode but only partially resolves this issue's expanded scope.

  2. altendky commented on Aug 31, 2026

    @altendky
    ContributorAuthor

    but hey, in favor of a clean issue list i'll close this. thanks!

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

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions