Custom flow fails to authenticate against GitLab API
<!--IssueSummary start-->
<details>
<summary>
Everyone can contribute. [Help move this issue forward](https://handbook.gitlab.com/handbook/marketing/developer-relations/contributor-success/community-contributors-workflows/#contributor-links) while earning points, leveling up and collecting rewards.
</summary>
- [Close this issue](https://contributors.gitlab.com/manage-issue?action=close&projectId=278964&issueIid=594248)
</details>
<!--IssueSummary end-->
### Summary
<!-- Summarize the bug encountered concisely. -->
### Steps to reproduce
I defined a custom flow to pull git submodules before running an MR Review.
It's a 2 steps flow, with 1. DeterministicStepComponent to pull git submodule, 2. AgentComponent to actually run the MR Review
When the flow starts, it installs `duo cli`, then tests SRT sandbox and starts defining its settings with `srt --settings /tmp/srt-settings.json duo run --existing-session-id 3197378 --connection-type websocket`.
This logs an error (without failing the job/pipeline) but fails the agent session without additional information.
Job logs:
```
2026-03-20T09:11:42:945 [error]: Error: Fetching version from https://gitlab.com/api/v4/version failed. The request requires higher privileges than provided by the access token.
at G91 (file:///usr/lib/node_modules/@gitlab/lib_core/src/fetch/handle_fetch_error.ts:10:11)
at processTicksAndRejections (node:internal/process/task_queues:95:5)
at wc.fetchFromApi (file:///usr/lib/node_modules/@gitlab/lib_core/src/gitlab_api/simple_api_client.ts:88:5)
at ry.#J (file:///usr/lib/node_modules/@gitlab/lib_core/src/feature_flags/instance_feature_flags.ts:229:27)
at ry.#G (file:///usr/lib/node_modules/@gitlab/lib_core/src/feature_flags/instance_feature_flags.ts:247:19)
at Object.<anonymous> (file:///usr/lib/node_modules/@gitlab/lib_core/src/feature_flags/instance_feature_flags.ts:98:7)
- Error details:
- REST Request:
- Method: GET
- Path: /api/v4/version
- Response:
- Status: 403
- Headers: {"cache-control":"no-cache","cf-cache-status":"MISS","cf-ray":"9df3974ce9efdd6f-ATL","connection":"close","content-encoding":"gzip","content-security-policy":"default-src 'none'","content-type":"application/json","date":"Fri, 20 Mar 2026 09:11:42 GMT","gitlab-lb":"haproxy-main-33-lb-gprd","gitlab-sv":"gke-cny-api","nel":"{\"max_age\": 0}","referrer-policy":"strict-origin-when-cross-origin","server":"cloudflare","set-cookie":"_cfuvid=d3P9XQzRNi2hhw2vIzOzG4zihaDhAE1WrSDPFBbqF0E-1773997902927-0.0.1.1-604800000; path=/; domain=.gitlab.com; HttpOnly; Secure; SameSite=None","strict-transport-security":"max-age=31536000","transfer-encoding":"chunked","vary":"Origin, Accept-Encoding","x-content-type-options":"nosniff","x-gitlab-meta":"{\"correlation_id\":\"9df3974ce9efdd6f-ATL\",\"version\":\"1\"}","x-request-id":"9df3974ce9efdd6f-ATL","x-runtime":"0.026915"}
- Response body: {"error":"insufficient_scope","error_description":"The request requires higher privileges than provided by the access token.","scope":"read_user ai_features api read_api"}
[...]
2026-03-20T09:11:43:428 [debug]: [DuoWorkflowNodeExecutor][3197378] websocket connection created successfully
2026-03-20T09:11:43:428 [info]: [MCP] Sandbox mode detected (GITLAB_WORKFLOW_SANDBOX=true) - skipping external MCP servers
2026-03-20T09:11:43:428 [info]: [DuoWorkflowNodeExecutor][3197378] startRequest: mcp_tools=0 preapproved_tools=0 servers=0
2026-03-20T09:11:43:428 [debug]: [DuoWorkflowNodeExecutor][3197378] startRequest: approved_tools=[]
2026-03-20T09:11:43:428 [debug]: [DuoWorkflowNodeExecutor][3197378] Writing startRequest to stream with CLIENT_CAPABILITIES: shell_command...
2026-03-20T09:11:43:431 [debug]: [DuoWorkflowNodeExecutor][3197378] startRequest write returned: true
2026-03-20T09:11:43:431 [debug]: [DuoWorkflowNodeExecutor][3197378] startRequest written to stream
2026-03-20T09:11:43:431 [debug]: [DuoWorkflowNodeExecutor][3197378] Entering event queue iteration...
2026-03-20T09:11:44:116 [debug]: [WebSocketWorkflowClient] WebSocket connection closed: {"code":1000,"reason":""}
2026-03-20T09:11:44:116 [debug]: [WebSocketWorkflowClient] Heartbeat stopped
2026-03-20T09:11:44:117 [debug]: [DuoWorkflowNodeExecutor][3197378] Stream end event received
2026-03-20T09:11:44:117 [debug]: [DuoWorkflowNodeExecutor][3197378] Event queue iteration completed
2026-03-20T09:11:44:117 [debug]: [PreConfiguredWorkflowTokenService] Ignoring revoke request for workflow "3197378" - pre-configured tokens cannot be revoked
2026-03-20T09:11:44:117 [info]: [GitLabBackend] Workflow completed successfully
2026-03-20T09:11:44:128 [info]: [CliExitHandler] Shutting down gracefully...
2026-03-20T09:11:44:129 [debug]: [PreConfiguredWorkflowTokenService] Disposed pre-configured token service
2026-03-20T09:11:44:129 [info]: [ExecutorManager] Disposing ExecutorManager (1 active executors)
2026-03-20T09:11:44:130 [debug]: [ExecutorManager] Disposing executor for workflow "3197378".
2026-03-20T09:11:44:130 [info]: [DuoWorkflowNodeExecutor][3197378] Disposing executor - starting shutdown
2026-03-20T09:11:44:130 [info]: [DuoWorkflowNodeExecutor][3197378] Force disconnecting - aborting any outstanding action handlers, ending stream
2026-03-20T09:11:44:131 [info]: [MCP Manager] Disposing service
2026-03-20T09:11:44:131 [info]: [DuoWorkflowNodeExecutor][3197378] Force disconnected
2026-03-20T09:11:44:132 [info]: [CliExitHandler] Shutdown complete, good bye :)
$ else
$ else
$ echo "Command execution completed with exit code: $?"
Command execution completed with exit code: 0
Cleaning up project directory and file based variables
00:00
Job succeeded
```
Session details:
```
Session information
AI Item: Ai catalog agent
Session ID: #3197378
Type: Flow
Project: nodejs-sample-gcp
Group: gcp
Triggered by: @odupre
Status:
Failed
Started: 20 Mar 2026, 09:54
Last updated: 20 Mar 2026, 10:11
Job ID: #13575593850
```
### Example Project
This happens on my project: https://gitlab.com/gl-demo-ultimate-odupre/gcp/nodejs-sample-gcp. I can grant you access if needed.
Here is the flow definition:
```
version: "v1"
environment: ambient
components:
# 1. Deterministic step to init submodules
- name: "git_submodules_init"
type: DeterministicStepComponent
tool_name: "run_git_command"
inputs:
- from: "git submodule update --init --recursive"
as: "command"
literal: true
# 2. Your MR review agent
- name: "custom_mr_review_agent"
type: AgentComponent
prompt_id: "custom_mr_review_prompt"
inputs:
- "context:goal"
toolset:
- "read_file"
- "read_files"
- "list_dir"
- "build_review_merge_request_context"
- "post_duo_code_review"
- "get_merge_request"
- "list_merge_request_diffs"
- "list_all_merge_request_notes"
- "create_merge_request_note"
ui_log_events:
- "on_agent_final_answer"
- "on_tool_execution_success"
prompts:
- prompt_id: "custom_mr_review_prompt"
name: "Custom MR Review"
unit_primitives: []
prompt_template:
system: |
You are GitLab Duo Chat, an agentic AI assistant.
Your role is to help users with their GitLab tasks.
Be concise, accurate, and actionable in your responses.
You are an experienced software engineer.
Review the MR and provide clear, actionable feedback.
user: |
{{goal}}
params:
timeout: 360
routers:
- from: "git_submodules_init"
to: "custom_mr_review_agent"
- from: "custom_mr_review_agent"
to: "end"
flow:
entry_point: "git_submodules_init"
```
### What is the current *bug* behavior?
The job succeeds despite an error in its logs.
The Agent session fails without clear and explicit explanation and without delivering expected results.
### What is the expected *correct* behavior?
* The job does not fail (access to GitLab API is authorized)
* The 2 steps of the Flow succeeds.
### Output of checks
<!-- If you are reporting a bug on GitLab.com, uncomment below -->
This bug happens on GitLab.com
<!-- and uncomment below if you have /label privileges -->
issue