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:
| Situation | Why there is no prompt |
|---|---|
copilot -p "..." non-interactive mode | The process exits after completion and never renders an interactive prompt |
| CI, cron, or a script with redirected stdin | There is no TTY to read a keypress from |
| A denial rule matched | Denials are final; there is nothing to approve |
| The tool was filtered out entirely | The tool is not available, so approval is not applicable |
| VS Code remote / SSH session reconnected | The 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
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
-prun 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_urlsand any--deny-toolyou 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=truein the job environment rather than sprinkling--yolothrough your steps.
Next Steps
- Fix Copilot CLI authorization errors if the failure is about your subscription or token rather than tool approval
- Use shell commands with Copilot CLI
- Integrate Copilot CLI with CI/CD