Skip to main content
Copilotintermediate

Fix "Permission denied and could not request permission from user"

Resolve `Permission denied and could not request permission from user` in GitHub Copilot CLI. Fix non-interactive -p mode, deny rules that override --allow-all-tools, path restrictions, and shell redirection approvals.

8 min readUpdated August 2026

GitHub Copilot CLI stops mid-task and reports:

Permission denied and could not request permission from user

The message has two halves, and both matter. Permission denied means a tool call was not authorized. Could not request permission from user means the CLI had no way to ask you — so instead of pausing for approval, it failed the call outright.

Why This Happens

Copilot CLI gates three separate things: which tools may run, which paths may be read or written, and which URLs may be accessed. When a gated action is not pre-approved, the CLI normally shows a prompt with Yes / Yes-and-approve-for-the-session / No. If that prompt cannot be displayed, you get this error.

The prompt cannot be displayed when:

SituationWhy there is no prompt
copilot -p "..." non-interactive modeThe process exits after completion and never renders an interactive prompt
CI, cron, or a script with redirected stdinThere is no TTY to read a keypress from
A denial rule matchedDenials are final; there is nothing to approve
The tool was filtered out entirelyThe tool is not available, so approval is not applicable
VS Code remote / SSH session reconnectedThe IPC channel to the extension went stale, so the request never reaches the UI

Fix 1: Pre-Approve Tools in Non-Interactive Mode

If you are using -p, you must tell the CLI up front what it may do:

# Allow tool calls to run without confirmation
copilot -p "Fix the failing test in src/parser.ts" --allow-all-tools

# Also allow file access outside the working directory
copilot -p "Update the changelog" --allow-all-tools --allow-all-paths

# Everything at once (equivalent to the three --allow-all-* flags)
copilot -p "Refactor the auth module" --allow-all
copilot -p "Refactor the auth module" --yolo

--allow-all-tools also has an environment variable, which is convenient in CI:

export COPILOT_ALLOW_ALL=true
copilot -p "Run the build and fix any type errors"

--allow-all and --yolo remove every confirmation. Use them where a bad decision is cheap: a container, a throwaway clone, or a CI job — not on a working copy with uncommitted changes.

Fix 2: Check for a Denial Rule That Beats Your Allow Flag

This is the case that confuses people, because the error persists even with --allow-all-tools. Denial rules always take precedence over allow rules, including --allow-all-tools.

Look for all three sources:

# 1. Flags on the command line
#    Remove any --deny-tool / --deny-url you are passing
copilot -p "..." --allow-all-tools --deny-tool 'shell(rm)'   # rm stays blocked

# 2. Persistent config
cat ~/.copilot/config.json
#    Check denied_urls, allowed_urls, trusted_folders

Also check whether the tool was filtered out rather than denied. --available-tools and --excluded-tools decide which tools the model can see; --allow-tool and --allow-all-tools only decide whether a visible tool needs approval. Allowing a tool you excluded does not bring it back:

# This blocks the shell tool no matter what you allow
copilot -p "..." --excluded-tools shell --allow-all-tools
Advertisement

Fix 3: Grant the Specific Permission Instead of All of Them

For repeatable runs, narrow allowances are safer than --yolo. Permission patterns take the form kind(argument):

# All git subcommands
copilot -p "Commit my changes" --allow-tool 'shell(git:*)'

# One exact command
copilot -p "Run the tests" --allow-tool 'shell(npm test)'

# File-creating and file-modifying tools (not shell invocations)
copilot -p "Add a README" --allow-tool 'write'

# A specific MCP server, or one tool from it
copilot -p "..." --allow-tool 'MyMCP' --allow-tool 'MyMCP(my_tool)'

Note the wildcard rule: matching is done on the command stem, so shell(git:*) matches git push but not gitea.

One trap worth knowing: the write kind matches tools that create and modify files, but not shell tool invocations. A shell command that redirects output (... > out.txt) is a shell invocation, so --allow-tool 'write' will not cover it. Use --allow-all-tools, or allow that specific shell command.

Fix 4: Widen Path Access

By default, file access is limited to the current working directory, its subdirectories, and the system temporary directory. A denial on a file outside that scope produces the same message.

# Grant one extra directory
copilot --add-dir /Users/you/shared-config

# Disable path verification entirely
copilot -p "..." --allow-all-paths

# Interactively, during a session
/add-dir /path/to/directory

If you need a directory trusted across sessions, add it to trusted_folders in ~/.copilot/config.json.

Fix 5: URL Denials Are Protocol-Aware

If the blocked action was a fetch, remember that approving a domain over HTTPS does not approve it over HTTP. Patterns without an explicit protocol default to https://.

copilot --allow-url github.com                  # https://github.com only
copilot --allow-url http://internal.example.com # http must be explicit
copilot --allow-url 'https://*.github.com'      # wildcard subdomains
copilot -p "..." --allow-all-urls

Fix 6: Restart After an SSH or Remote Reconnect

If this started after a network blip in a VS Code Remote-SSH session or dev container, the CLI process is holding a stale IPC file descriptor while the extension has moved to a new connection. Approval requests are sent into a channel nobody is listening on, and every retry fails the same way.

Reload the window or restart the Copilot CLI process. Nothing about your permission configuration needs to change.

Verify the Fix

# Confirm what the CLI thinks your permission model is
copilot help permissions

# Inspect persistent settings
cat ~/.copilot/config.json

# Re-run with debug logging and read the denial
copilot -p "..." --allow-all-tools --log-level all
tail -n 100 ~/.copilot/logs/*.log

The log tells you which specific tool call was refused, which is far faster than guessing at flags.

Prevent It Coming Back

  • Any -p run needs its permissions declared on the command line; interactive defaults do not carry over.
  • Keep persistent allowances in ~/.copilot/config.json (trusted_folders, allowed_urls) so scripted runs do not need long flag lists.
  • Audit denied_urls and any --deny-tool you have wired into a wrapper script before blaming the allow flags.
  • Run the CLI from the repository root so the default path scope already covers the files it needs.
  • In CI, set COPILOT_ALLOW_ALL=true in the job environment rather than sprinkling --yolo through your steps.

Next Steps

Frequently Asked Questions

Find answers to common questions

Copilot CLI tried to run a tool it was not pre-approved to use, and it had no way to show you an approval prompt. That happens in non-interactive mode (-p), in CI, or when the terminal cannot accept input. The tool call fails instead of pausing.

Denial rules always take precedence over allow rules, including --allow-all-tools. A --deny-tool flag, a denied_urls entry in ~/.copilot/config.json, or a tool filtered out by --available-tools or --excluded-tools will still be blocked.

Pre-approve everything the run needs. Use 'copilot -p "..." --allow-all-tools' for tool calls, add --allow-all-paths if it must touch files outside the working directory, and --allow-all-urls for network fetches. --allow-all (or --yolo) enables all three.

--available-tools and --excluded-tools decide which tools the model can see at all. --allow-tool, --deny-tool and --allow-all-tools decide whether a visible tool needs an approval prompt. Allowing a tool that was filtered out does not bring it back.

The 'write' permission kind matches tools that create and modify files, but not shell tool invocations. Shell redirections are covered by --allow-all-tools, or by an explicit shell(...) pattern for that command.

Use permission patterns: --allow-tool 'shell(git:*)' allows all git subcommands, --allow-tool 'shell(npm test)' allows one exact command, and --allow-tool 'write' allows file-modifying tools. Denial rules still win over any of these.

File access is restricted by default to the current working directory, its subdirectories, and the system temp directory. Use --add-dir to grant a specific extra directory, or --allow-all-paths to disable the check entirely.

Choosing "Yes, and approve for rest of session" lasts only for that session. For persistence, add the folder to trusted_folders or the domain to allowed_urls in ~/.copilot/config.json, or pass the flags each run.

--yolo and --allow-all are equivalent to --allow-all-tools --allow-all-paths --allow-all-urls. They remove every confirmation, so reserve them for scripted runs in a container, a scratch clone, or CI — not your primary working copy.

The extension talks to the CLI process over an IPC channel. After an SSH drop and reconnect, the CLI can hold a stale file descriptor while the extension has moved to a new connection, so approval requests never reach you. Restart the Copilot CLI process or reload the window.