Skip to content

tools: optional search metadata breaks pending permission listing #37650

Description

@kitlangton

Summary

Pending glob and grep permissions can make session.permission.list fail schema encoding when optional tool inputs are omitted. The tools store absent optional fields as undefined inside JSON permission metadata.

Environment

  • opencode version: opencode2 v0.0.0-next-15798
  • OS: Darwin 25.5.0, arm64
  • Terminal: WarpTerminal, TERM=xterm-256color, COLORTERM=truecolor
  • Shell: /bin/zsh
  • Install/channel: local development checkout; reproduced on V2 1f2de535aa and Quark 196892c165
  • Active plugins: isolated OpenCode Drive simulation plugin only

Reproduction

  1. Configure permissions to ask by default:

    {
      "permissions": [{ "action": "*", "resource": "*", "effect": "ask" }]
    }
  2. Emit a glob tool call without the optional path and limit fields:

    {
      "name": "glob",
      "input": { "pattern": "**/*.txt" }
    }
  3. While the permission is pending, request session.permission.list for the session.

The deterministic Drive reproduction is in multi-tool-interleavings.ts. Removing the explicit path or limit from the glob input reproduces the failure consistently.

Expected Behavior

The permission request should omit absent optional metadata fields, and session.permission.list should return all pending permissions.

Actual Behavior

The endpoint rejects its response body:

Expected JSON value, got undefined
  at ["data"][1]["metadata"]["path"]

Supplying path but omitting limit moves the same failure to:

Expected JSON value, got undefined
  at ["data"][1]["metadata"]["limit"]

Additional Context

packages/core/src/tool/glob.ts currently constructs:

metadata: {
  root: input.path ?? ".",
  path: input.path,
  limit: input.limit,
}

packages/core/src/tool/grep.ts has the same pattern for optional path, include, and limit fields. Permission metadata is JSON, so these keys should be conditionally included or sanitized before persistence/encoding.

The screenshot shows the concurrent permission state used to discover the failure:

permission-over-form.png

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