can1357/oh-my-pi · error · AIError.ProviderResponseError

GitLab Duo Workflow create response missing workflow id (HTT

Error message

GitLab Duo Workflow create response missing workflow id (HTTP ${response.status})

What it means

Thrown when the create-workflow call returns HTTP ok but the parsed GitLabCreateWorkflowResponse has no id in any known field (id, workflow_id, workflowId). Without a workflow id the client cannot stream events for the workflow, so it fails fast with a ProviderResponseError (kind: empty-body), including the HTTP status for context.

Source

Thrown at packages/ai/src/providers/gitlab-duo-workflow.ts:1730

		body: JSON.stringify(body),
		signal: gitLabDuoWorkflowRestSignal(signal),
	});
	traceGitLabDuoWorkflow("workflow.create.response", {
		status: response.status,
		ok: response.ok,
		namespaceId,
		hasProjectId: Boolean(projectId),
	});
	if (!response.ok) {
		throw new AIError.GitLabDuoWorkflowApiError(
			`GitLab Duo Workflow create failed with HTTP ${response.status}`,
			response.status,
		);
	}
	const payload = (await response.json()) as GitLabCreateWorkflowResponse;
	const workflowId = payload.id ?? payload.workflow_id ?? payload.workflowId;
	if (workflowId === undefined) {
		throw new AIError.ProviderResponseError(
			`GitLab Duo Workflow create response missing workflow id (HTTP ${response.status})`,
			{ provider: "gitlab-duo-agent", kind: "empty-body" },
		);
	}
	traceGitLabDuoWorkflow("workflow.create.id", { workflowId });
	return String(workflowId);
}

async function stopGitLabDuoWorkflow(
	fetchImpl: FetchImpl,
	baseUrl: string,
	apiKey: string,
	workflowId: string,
): Promise<void> {
	// Stop rides a FRESH timeout signal, deliberately decoupled from `options.signal`
	// (see the `finally` block in `runGitLabDuoWorkflow`): a run cancelled by the
	// caller must still fire the server-side stop, but a stalled PATCH here would
	// otherwise leave the `runGitLabDuoWorkflow` promise unresolved forever — the

View on GitHub (pinned to 9690622007)

Solutions

  1. Check the raw create response with curl against your GitLab instance to see where the id lives
  2. Upgrade GitLab (or pi-ai) so the create response field names match what the client recognizes
  3. Bypass any proxy/cache that might strip the response body
  4. Retry — if the Duo Workflow service was mid-restart it may return a complete body next time
Defensive patterns

Strategy: type-guard

Validate before calling

// Confirm the create endpoint returns an id field on your GitLab version:
const probe = await fetch(`${gitlabBaseUrl}/api/v4/version`, { headers: { authorization: `Bearer ${token}` } });
const { version } = await probe.json();
if (compareVersion(version, "16.x") < 0) console.warn("GitLab version may lack workflow id in create response");

Type guard

function hasWorkflowId(p: GitLabCreateWorkflowResponse): p is GitLabCreateWorkflowResponse & { id: string | number } {
  return (p.id ?? p.workflow_id ?? p.workflowId) !== undefined;
}

Try / catch

try {
  const workflowId = await createWorkflow(...);
} catch (err) {
  if (err instanceof AIError.ProviderResponseError && err.message.includes("missing workflow id")) {
    // inspect the raw create response body for the actual id field name / GitLab version drift
  } else throw err;
}

Prevention

When it happens

Trigger: GitLab accepted the create but returned a body without the workflow id — GitLab version whose create response uses an unrecognized field name, a partial/empty 2xx body from a proxy, or Duo Workflow service returning an ack-only body.

Common situations: Self-managed GitLab version mismatch with the client's expected response schema; intermediary caching proxy serving a stripped body; Duo Workflow service degraded while the front door still returns 2xx.

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/350a299583ce902a. Report an issue: GitHub.