can1357/oh-my-pi · error · AIError.ProviderResponseError
GitLab Duo Workflow direct_access did not return credentials
Error message
GitLab Duo Workflow direct_access did not return credentials
What it means
Thrown when the direct_access endpoint returns HTTP 200 but the JSON payload contains no usable workflow token — extractGitLabWorkflowToken finds nothing in payload.gitlab_rails, payload.duo_workflow_service, etc. Without credentials the client cannot talk to the Duo Workflow service, so it fails with a ProviderResponseError (kind: empty-body).
Source
Thrown at packages/ai/src/providers/gitlab-duo-workflow.ts:1674
if (!response.ok) {
const message = await readGitLabDuoWorkflowResponseErrorMessage(response);
// Always embed the HTTP status, even when the body carries a message: the
// streaming auth-retry/rotation path (`extractStatusFromAssistantError` ->
// `extractHttpStatusFromError`) refreshes/rotates broker credentials only
// when the assistant error exposes `errorStatus` or the message embeds an
// `HTTP <status>` token. A 401 `{"message":"Unauthorized"}` or a 429 quota
// body would otherwise surface as a hard failure with no recoverable status.
throw new AIError.GitLabDuoWorkflowApiError(
message
? `GitLab Duo Workflow direct_access failed with HTTP ${response.status}: ${message}`
: `GitLab Duo Workflow direct_access failed with HTTP ${response.status}`,
response.status,
);
}
const payload = (await response.json()) as GitLabDirectAccessResponse;
const token = extractGitLabWorkflowToken(payload);
if (!token) {
throw new AIError.ProviderResponseError("GitLab Duo Workflow direct_access did not return credentials", {
provider: "gitlab-duo-agent",
kind: "empty-body",
});
}
traceGitLabDuoWorkflow("direct_access.token", { hasToken: true });
const serviceEndpoint = !payload.gitlab_rails?.token && Boolean(payload.duo_workflow_service?.base_url);
return {
token,
...(serviceEndpoint && payload.duo_workflow_service?.base_url
? { baseUrl: normalizeGitLabDuoWorkflowServiceBaseUrl(payload.duo_workflow_service.base_url) }
: {}),
headers: serviceEndpoint ? (payload.duo_workflow_service?.headers ?? {}) : {},
serviceEndpoint,
};
}
async function createGitLabDuoWorkflow(
fetchImpl: FetchImpl,View on GitHub (pinned to 9690622007)
Solutions
- Confirm Duo Workflow is enabled for your GitLab instance and project/namespace
- Compare your GitLab version's direct_access response shape with what the client expects; upgrade pi-ai or GitLab as needed
- Check for a proxy stripping the response body and bypass it
- Call direct_access manually with curl to inspect the raw JSON payload
Defensive patterns
Strategy: validation
Validate before calling
// Confirm Duo Workflow is provisioned before calling direct_access:
const res = await fetch(`${gitlabBaseUrl}/api/v4/profile`, { headers: { authorization: `Bearer ${token}` } });
const profile = await res.json();
if (!profile) throw new Error("GitLab token has no profile access — Duo Workflow likely unprovisioned"); Type guard
function hasWorkflowToken(p: unknown): p is GitLabDirectAccessResponse & { token: string } {
return typeof p === "object" && p !== null && extractGitLabWorkflowToken(p as GitLabDirectAccessResponse) !== undefined;
} Try / catch
try {
await requestDirectAccess(...);
} catch (err) {
if (err instanceof AIError.ProviderResponseError && err.message.includes("did not return credentials")) {
throw new Error("Duo Workflow credentials missing — enable Duo Workflow for this namespace/project or check GitLab version");
}
throw err;
} Prevention
- Enable Duo Workflow on your GitLab project/namespace before using the provider
- Match GitLab server version to what the pi-ai client expects
- Bypass stripping proxies for the direct_access route
- Verify with curl that direct_access returns token fields before wiring up the client
When it happens
Trigger: direct_access responds ok but the body lacks any recognized token fields — Duo Workflow service not provisioned for the namespace, GitLab version returning a different response shape, or an empty object returned by a proxy.
Common situations: GitLab project/group without Duo Workflow activated; older self-managed GitLab whose direct_access response schema differs from what the client expects; intermediary (proxy/gateway) swallowing the body.
Related errors
- GitLab Duo Workflow create response missing workflow id (HTT
- ${source} response has a missing or invalid Expiration.
- Unable to resolve AWS credentials. Configure static environm
- profile
- Devin API error: response body is empty
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/669cc50dbf7e6d26.
Report an issue: GitHub.