can1357/oh-my-pi · error · Error

Unable to find a GitLab Duo Workflow namespace with availabl

Error message

Unable to find a GitLab Duo Workflow namespace with available models. Set GITLAB_DUO_NAMESPACE_ID to a root namespace with Duo model access.

What it means

Thrown by selectGitLabDuoWorkflowNamespace when every candidate namespace was rejected by validateNamespaceCandidate — i.e. namespaces were found, but none offers available Duo Workflow models. Unlike the runtime-namespace error, configuration was resolvable but yielded no usable models.

Source

Thrown at packages/catalog/src/discovery/gitlab-duo-workflow.ts:215

export function buildGitLabDuoWorkflowFallbackModel(
	id = FALLBACK_MODEL_ID,
	name = FALLBACK_MODEL_NAME,
	baseUrl = GITLAB_DEFAULT_BASE_URL,
): ModelSpec<"gitlab-duo-agent"> {
	return buildGitLabDuoWorkflowModelSpec({ name, ref: id }, baseUrl);
}

async function selectGitLabDuoWorkflowNamespace(
	config: GitLabDuoWorkflowDiscoveryConfig,
): Promise<GitLabDuoWorkflowNamespaceSelectionWithModels> {
	const baseUrl = normalizeGitLabBaseUrl(config.baseUrl);
	const selection = await selectGitLabDuoWorkflowCandidate(config, baseUrl, candidate =>
		validateNamespaceCandidate(config, baseUrl, candidate),
	);
	if (selection) {
		return selection;
	}
	throw new Error(
		"Unable to find a GitLab Duo Workflow namespace with available models. Set GITLAB_DUO_NAMESPACE_ID to a root namespace with Duo model access.",
	);
}

type GitLabDuoWorkflowCandidateResolver<TSelection> = (
	candidate: GitLabDuoWorkflowCandidate,
) => Promise<TSelection | null> | TSelection | null;

async function selectGitLabDuoWorkflowCandidate<TSelection>(
	config: GitLabDuoWorkflowDiscoveryConfig,
	baseUrl: string,
	resolveCandidate: GitLabDuoWorkflowCandidateResolver<TSelection>,
	enrichNamespaceOverride = false,
): Promise<TSelection | null> {
	const namespaceId = normalizeIdentifier(config.namespaceId) ?? normalizeIdentifier(Bun.env.GITLAB_DUO_NAMESPACE_ID);
	if (namespaceId) {
		const candidate = enrichNamespaceOverride
			? ((await fetchNamespaceOverrideCandidate(config, baseUrl, namespaceId)) ?? {

View on GitHub (pinned to 9690622007)

Solutions

  1. Point GITLAB_DUO_NAMESPACE_ID at a root namespace whose plan includes Duo model access.
  2. Confirm in the GitLab UI that Duo Chat/Workflow models are listed for that namespace.
  3. Check the token belongs to a user with Developer+ access in that namespace and Duo enabled.

Example fix

// before: subgroup without Duo models
GITLAB_DUO_NAMESPACE_ID=my-group/sub-team
// after: root namespace with Duo access
GITLAB_DUO_NAMESPACE_ID=my-group
Defensive patterns

Strategy: try-catch

Validate before calling

null

Type guard

null

Try / catch

try {
  const sel = await selectGitLabDuoWorkflowNamespace(config);
} catch (err) {
  if (err.message.includes("namespace with available models")) {
    // namespace resolved but has no Duo models — check plan/licensing
    logger.error("GitLab namespace has no Duo models", { namespace: process.env.GITLAB_DUO_NAMESPACE_ID });
  }
  throw err;
}

Prevention

When it happens

Trigger: selectGitLabDuoWorkflowNamespace/selection where each candidate namespace fails model validation (empty model list, no Duo access on the namespace, or API returning models the validator filters out).

Common situations: Namespace lacks a Duo Workflow subscription/seat; GITLAB_DUO_NAMESPACE_ID points to a subgroup (not root) without model access; self-managed instance without duo features licensed; token scopes fine but the account isn't a Duo beta/entitled member.

Related errors


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