[BUG] Free models fail when `shell` or `read` permissions are denied · Issue #51241 · anomalyco/opencode · GitHub
Skip to content

[BUG] Free models fail when shell or read permissions are denied #51241

Open

Description

@Otagamo

Description

Free models fail when shell or read permissions are denied

Description

Using OpenCode v2.0.16 with OpenCode free models such as opencode/big-pickle.

If either the shell or read permission is set to deny, requests to free models fail with:

Error: OpenCode's free tier can only be used from within OpenCode

For example:

{
  "action": "shell",
  "resource": "*",
  "effect": "deny"
},
{
  "action": "read",
  "resource": "*",
  "effect": "deny"
}

Changing both permissions to allow immediately makes the error disappear:

{
  "action": "shell",
  "resource": "*",
  "effect": "allow"
},
{
  "action": "read",
  "resource": "*",
  "effect": "allow"
}

The behavior can be reproduced without restarting OpenCode: changing these permissions while OpenCode is running changes whether the next request succeeds or fails.

Expected behavior

Tool permissions should control whether the model can use those tools.

Denying shell or read should not cause a request made from the official OpenCode CLI to be identified as coming from outside OpenCode.

Actual behavior

Disabling these tools causes OpenCode free-tier requests to be rejected as if the request were not originating from OpenCode.

Environment

  • OpenCode: v2.0.16

Plugins

Reproduced with the official CLI. The behavior is permission-dependent.

OpenCode version

2.0.16

Steps to reproduce

  1. Run OpenCode v2.0.16.
  2. Select a free OpenCode model, for example opencode/big-pickle.
  3. Set shell or read to deny.
  4. Start a new session or send a simple prompt such as Hello.
  5. The request fails with:
Error: OpenCode's free tier can only be used from within OpenCode
  1. Change both shell and read to allow.
  2. Send the same prompt again.
  3. The request succeeds.

Screenshot and/or share link

No response

Operating System

Windows 11 25H2 26200.9457

Terminal

PowerShell 7.6.6.0-x64

Activity

  1. changed the title [-]Free models fail when `shell` or `read` permissions are denied[/-] [+][BUG] Free models fail when `shell` or `read` permissions are denied[/+] on Sep 25, 2026
  2. holny commented on Sep 27, 2026

    @holny
    Contributor

    I'll take this. Denying shell or read shouldn't trip the free-tier provenance check — those two sounds like they feed the same environment/header path that proves the request came from OpenCode, so a deny probably short-circuits something that looks like client identity to the gateway.

    I'll trace where a denied shell/read permission changes what the CLI sends (headers or body) on free-tier requests, fix it so permissions only affect tool availability, and add a regression test that runs with both denied and asserts the request still goes out as an official client.

    Fixes #51241

  3. holny commented on Sep 27, 2026

    @holny
    Contributor

    Update after digging: I couldn't find any client path where a denied shell/read permission changes what the CLI sends — the free-tier provenance check is enforced by the Zen gateway against the config the CLI pulls from the console (plugin/provider/opencode.ts builds its headers from that remote config, independent of tool permissions). I also can't reproduce the gateway's decision locally without a free-tier credential, so I'm stepping back from this one rather than guess at a client fix. Gateway-side investigation (why a denied tool flips provenance) is probably where this lands.

  4. Mike-Rice commented on Sep 30, 2026

    @Mike-Rice

    Confirming on opencode 1.18.33 (V1), built-in opencode provider, opencode/big-pickle, empty project:

    • permission.bash: "deny" → Error: OpenCode's free tier can only be used from within OpenCode
    • permission.bash: "ask" → works
    • tools.bash: false also reproduces

    Root cause is the absent bash tool in the outgoing request (see #50627 and #51315). ask (or allow) is the workaround.

  5. Dioarya commented on Oct 5, 2026

    @Dioarya

    Repro'd on Windows with scoop install main/opencode, opencode version 1.18.34, empty project.
    C:\Users\<User>\.config\opencode\opencode.jsonc

    {
      "$schema": "https://opencode.ai/config.json",
      "permission": {
        "*": "deny"
      }
    }

    and

    {
      "$schema": "https://opencode.ai/config.json",
      "permission": "deny"
    }
  6. Otagamo commented on Oct 10, 2026

    @Otagamo
    Author

    Is it possible to escalate this issue to the proper channel?

    Two weeks have passed with no attempt at a fix.

  7. hellovalerie commented on Oct 16, 2026

    @hellovalerie

    Data point you flagged as unchecked on 1.19.0: the narrow read allow pattern works, and it is a complete workaround. No paid tier needed.

    What triggers the 403

    read must have at least one surviving allow. Deny-all — in any form — removes the tool from the request and trips the check.

    read config result
    "deny" 403
    {"*": "deny"} 403
    {"*": "deny", "<one path>": "allow"} OK
    "ask" OK
    "allow" OK

    Measured 1.19.0, --standalone, same account/model throughout. Reproducible 5/5.

    The deny actually holds

    Verified behaviourally, not just by absence of a 403 — with a canary file and a directory listing:

    read: {"*":"deny", "/nonexistent-scribe-allowlist/*": "allow"}
      → reading the canary:      refused, permission.rejected
      → listing /tmp and /Users: refused, permission.rejected
      → no canary in any output
      → a real dispatch produced a correct record
    

    So the tool stays in the request (satisfying the server-side check) while the agent is genuinely blind. Pointing the surviving allow at a path that never exists gives full blindness with no reachable surface.

    One behaviour worth noting

    With write/edit also denied, a terse instruction like "output a line" can make the model conclude it cannot "write the record" and refuse, rather than emitting the markdown as chat text. A prompt that says explicitly "output only markdown" avoided this every time. So the two interact: strict blindness makes an ambiguous instruction read as an impossible task, not as an instruction to reply.

    Related: #50627, and the original #55653 (now closed as a duplicate of this one).

    Co-Authored-By: opencode/space-bunny-free noreply@opencode.ai

  8. its-tahir commented on Oct 21, 2026

    @its-tahir

    Re-tested on OpenCode CLI v2.1.2 (Windows 11, signed out, opencode run --standalone, empty project, isolated config dir, model opencode/deepseek-v4.1-flash-free), one setting per run. What has changed since the 1.19.0 results above:

    • bash/shell/edit deny no longer triggers it on v2.1.2. Only read does.
    • read still triggers it in every form I tried: "read": "deny", "*": "deny", "tools": { "read": false }, an agent-level read deny (agent.build.permission.read), and a read deny in the project's ./opencode.json with a clean global config.
    Config Result
    no config OK
    "permission": { "read": "deny" } free-tier error
    "permission": { "*": "deny" } free-tier error
    "tools": { "read": false } free-tier error
    agent-level read deny free-tier error
    read deny in project ./opencode.json only free-tier error
    "permission": { "read": "ask" } OK
    "permission": { "bash": "deny" } / shell / edit OK

    The project-level case matters: a cloned repo's opencode.json can break free models without any change to your own config. opencode debug config shows which file the rule comes from (it appears as {"action": "read", "resource": "*", "effect": "deny"}).

    Fix: "ask" works on the next request. If you need read truly denied, @hellovalerie's narrow-allow pattern above keeps the deny in effect.

    Full write-up, including the separate "detected abusive traffic from this IP address" block: https://www.its-tahir.com/blog/opencode-free-tier-can-only-be-used-from-within-opencode

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

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions