argoproj/argo-workflows · error

Should specify a node when we get archived logs

Error message

Should specify a node when we get archived logs

What it means

getContainerLogsFromArtifact fetches logs from stored log artifacts instead of live pods. When the workflow has no matching log artifact (hasArtifactLogs is false) and no nodeId was supplied, the service cannot disambiguate which archived pod's logs to fetch, so it throws this error. It guards the archived-logs path where a node identifier is mandatory.

Source

Thrown at ui/src/shared/services/workflows-service.ts:244

    },

    async isWorkflowNodePendingOrRunning(workflow: Workflow, nodeId?: string) {
        // We always refresh the workflow rather than inspecting the state locally since it doubles
        // as a check to determine whether or not the API is currently reachable
        const updatedWorkflow = await this.get(workflow.metadata.namespace, workflow.metadata.name);
        const node = updatedWorkflow.status.nodes[nodeId];
        if (!node) {
            return !updatedWorkflow.status || ['Pending', 'Running'].includes(updatedWorkflow.status.phase);
        }
        return isNodePendingOrRunning(node);
    },

    getContainerLogsFromArtifact(workflow: Workflow, nodeId: string, container: string, grep: string, archived: boolean): Observable<LogEntry> {
        return of(hasArtifactLogs(workflow, nodeId, container)).pipe(
            switchMap(isArtifactLogs => {
                if (!isArtifactLogs) {
                    if (!nodeId) {
                        throw new Error('Should specify a node when we get archived logs');
                    }
                    throw new Error('no artifact logs are available');
                }

                return from(requests.get(this.getArtifactLogsPath(workflow, nodeId, container, archived)));
            }),
            mergeMap(r => r.text.split('\n')),
            map(content => ({content, podName: workflow.status.nodes[nodeId].displayName}) as LogEntry),
            filter(x => !!x.content.match(grep))
        );
    },

    getContainerLogs(workflow: Workflow, podName: string, nodeId: string, container: string, grep: string, archived: boolean): Observable<LogEntry> {
        const getLogsFromArtifact = () => this.getContainerLogsFromArtifact(workflow, nodeId, container, grep, archived);
        const getLogsFromCluster = () => this.getContainerLogsFromCluster(workflow, podName, container, grep);

        // If our workflow was deleted, try to get logs from artifacts.
        if (!isWorkflowInCluster(workflow)) {

View on GitHub (pinned to 35bff19146)

Solutions

  1. Pass the workflow node's ID (workflow.status.nodes[...].id) as the nodeId argument to getLogsFromArtifact.
  2. Verify the node actually produced log artifacts by checking workflow.status.nodes[nodeId].id for a outputs.artifacts entry with artifactLogs.
  3. If logs are genuinely absent, show a 'no artifact logs are available' message instead of retrying.

Example fix

// before
getLogsFromArtifact(wf, '', 'main', '', true);
// after
const nodeId = Object.values(wf.status.nodes).find(n => n.templateName === 'main')?.id;
getLogsFromArtifact(wf, nodeId, 'main', '', true);
Defensive patterns

Strategy: validation

Validate before calling

if (!nodeId || !workflow.status?.nodes?.[nodeId]) {
  throw new Error('nodeId is required to fetch archived logs');
}
getContainerLogsFromArtifact(workflow, nodeId, container, grep, archived);

Type guard

function hasNode(wf: Workflow, nodeId: string): boolean {
  return !!wf.status?.nodes && nodeId in wf.status.nodes;
}

Try / catch

try {
  await getLogsFromArtifact(wf, nodeId, container, grep, archived).toPromise();
} catch (e) {
  if (e.message.includes('Should specify a node')) {
    logger.warn('Cannot fetch archived logs without a node ID');
  }
}

Prevention

When it happens

Trigger: Calling getContainerLogsFromArtifact (via getLogsFromArtifact) with archived=true or no live pod available, when hasArtifactLogs returns false AND the nodeId argument is an empty string.

Common situations: Viewing logs for an archived workflow whose node ID was never recorded in the UI state; passing only a pod name or container name while omitting nodeId; resuming a deleted workflow where node IDs were lost.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


AI-assisted analysis of argoproj/argo-workflows@35bff19146 (2026-09-03). Data as JSON: /api/errors/3a11aa155e4142b6. Report an issue: GitHub.