{"record":{"id":"350a299583ce902a","repo":"can1357/oh-my-pi","slug":"gitlab-duo-workflow-create-response-missing-workfl","errorCode":null,"errorMessage":"GitLab Duo Workflow create response missing workflow id (HTTP ${response.status})","messagePattern":"GitLab Duo Workflow create response missing workflow id \\(HTTP (.+?)\\)","errorType":"exception","errorClass":"AIError.ProviderResponseError","httpStatus":null,"severity":"error","filePath":"packages/ai/src/providers/gitlab-duo-workflow.ts","lineNumber":1730,"sourceCode":"\t\tbody: JSON.stringify(body),\n\t\tsignal: gitLabDuoWorkflowRestSignal(signal),\n\t});\n\ttraceGitLabDuoWorkflow(\"workflow.create.response\", {\n\t\tstatus: response.status,\n\t\tok: response.ok,\n\t\tnamespaceId,\n\t\thasProjectId: Boolean(projectId),\n\t});\n\tif (!response.ok) {\n\t\tthrow new AIError.GitLabDuoWorkflowApiError(\n\t\t\t`GitLab Duo Workflow create failed with HTTP ${response.status}`,\n\t\t\tresponse.status,\n\t\t);\n\t}\n\tconst payload = (await response.json()) as GitLabCreateWorkflowResponse;\n\tconst workflowId = payload.id ?? payload.workflow_id ?? payload.workflowId;\n\tif (workflowId === undefined) {\n\t\tthrow new AIError.ProviderResponseError(\n\t\t\t`GitLab Duo Workflow create response missing workflow id (HTTP ${response.status})`,\n\t\t\t{ provider: \"gitlab-duo-agent\", kind: \"empty-body\" },\n\t\t);\n\t}\n\ttraceGitLabDuoWorkflow(\"workflow.create.id\", { workflowId });\n\treturn String(workflowId);\n}\n\nasync function stopGitLabDuoWorkflow(\n\tfetchImpl: FetchImpl,\n\tbaseUrl: string,\n\tapiKey: string,\n\tworkflowId: string,\n): Promise<void> {\n\t// Stop rides a FRESH timeout signal, deliberately decoupled from `options.signal`\n\t// (see the `finally` block in `runGitLabDuoWorkflow`): a run cancelled by the\n\t// caller must still fire the server-side stop, but a stalled PATCH here would\n\t// otherwise leave the `runGitLabDuoWorkflow` promise unresolved forever — the","sourceCodeStart":1712,"sourceCodeEnd":1748,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/ai/src/providers/gitlab-duo-workflow.ts#L1712-L1748","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Check the raw create response with curl against your GitLab instance to see where the id lives","Upgrade GitLab (or pi-ai) so the create response field names match what the client recognizes","Bypass any proxy/cache that might strip the response body","Retry — if the Duo Workflow service was mid-restart it may return a complete body next time"],"exampleFix":null,"handlingStrategy":"type-guard","validationCode":"// Confirm the create endpoint returns an id field on your GitLab version:\nconst probe = await fetch(`${gitlabBaseUrl}/api/v4/version`, { headers: { authorization: `Bearer ${token}` } });\nconst { version } = await probe.json();\nif (compareVersion(version, \"16.x\") < 0) console.warn(\"GitLab version may lack workflow id in create response\");","typeGuard":"function hasWorkflowId(p: GitLabCreateWorkflowResponse): p is GitLabCreateWorkflowResponse & { id: string | number } {\n  return (p.id ?? p.workflow_id ?? p.workflowId) !== undefined;\n}","tryCatchPattern":"try {\n  const workflowId = await createWorkflow(...);\n} catch (err) {\n  if (err instanceof AIError.ProviderResponseError && err.message.includes(\"missing workflow id\")) {\n    // inspect the raw create response body for the actual id field name / GitLab version drift\n  } else throw err;\n}","preventionTips":["Match GitLab server version with what the pi-ai client expects for create responses","Log the raw create JSON on 2xx to catch schema drift early","Bypass caching proxies that could serve a stripped 2xx body","Retry once — a restarting Duo Workflow service can return a partial body"],"tags":["gitlab","empty-response","workflow","provider-response"],"backgroundTag":"empty-response-body","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}