{"record":{"id":"3a11aa155e4142b6","repo":"argoproj/argo-workflows","slug":"should-specify-a-node-when-we-get-archived-logs","errorCode":null,"errorMessage":"Should specify a node when we get archived logs","messagePattern":"Should specify a node when we get archived logs","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"ui/src/shared/services/workflows-service.ts","lineNumber":244,"sourceCode":"    },\n\n    async isWorkflowNodePendingOrRunning(workflow: Workflow, nodeId?: string) {\n        // We always refresh the workflow rather than inspecting the state locally since it doubles\n        // as a check to determine whether or not the API is currently reachable\n        const updatedWorkflow = await this.get(workflow.metadata.namespace, workflow.metadata.name);\n        const node = updatedWorkflow.status.nodes[nodeId];\n        if (!node) {\n            return !updatedWorkflow.status || ['Pending', 'Running'].includes(updatedWorkflow.status.phase);\n        }\n        return isNodePendingOrRunning(node);\n    },\n\n    getContainerLogsFromArtifact(workflow: Workflow, nodeId: string, container: string, grep: string, archived: boolean): Observable<LogEntry> {\n        return of(hasArtifactLogs(workflow, nodeId, container)).pipe(\n            switchMap(isArtifactLogs => {\n                if (!isArtifactLogs) {\n                    if (!nodeId) {\n                        throw new Error('Should specify a node when we get archived logs');\n                    }\n                    throw new Error('no artifact logs are available');\n                }\n\n                return from(requests.get(this.getArtifactLogsPath(workflow, nodeId, container, archived)));\n            }),\n            mergeMap(r => r.text.split('\\n')),\n            map(content => ({content, podName: workflow.status.nodes[nodeId].displayName}) as LogEntry),\n            filter(x => !!x.content.match(grep))\n        );\n    },\n\n    getContainerLogs(workflow: Workflow, podName: string, nodeId: string, container: string, grep: string, archived: boolean): Observable<LogEntry> {\n        const getLogsFromArtifact = () => this.getContainerLogsFromArtifact(workflow, nodeId, container, grep, archived);\n        const getLogsFromCluster = () => this.getContainerLogsFromCluster(workflow, podName, container, grep);\n\n        // If our workflow was deleted, try to get logs from artifacts.\n        if (!isWorkflowInCluster(workflow)) {","sourceCodeStart":226,"sourceCodeEnd":262,"githubUrl":"https://github.com/argoproj/argo-workflows/blob/35bff19146f5a6ada77468c431f2624bd577e373/ui/src/shared/services/workflows-service.ts#L226-L262","documentation":"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.","triggerScenarios":"Calling getContainerLogsFromArtifact (via getLogsFromArtifact) with archived=true or no live pod available, when hasArtifactLogs returns false AND the nodeId argument is an empty string.","commonSituations":"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.","solutions":["Pass the workflow node's ID (workflow.status.nodes[...].id) as the nodeId argument to getLogsFromArtifact.","Verify the node actually produced log artifacts by checking workflow.status.nodes[nodeId].id for a outputs.artifacts entry with artifactLogs.","If logs are genuinely absent, show a 'no artifact logs are available' message instead of retrying."],"exampleFix":"// before\ngetLogsFromArtifact(wf, '', 'main', '', true);\n// after\nconst nodeId = Object.values(wf.status.nodes).find(n => n.templateName === 'main')?.id;\ngetLogsFromArtifact(wf, nodeId, 'main', '', true);","handlingStrategy":"validation","validationCode":"if (!nodeId || !workflow.status?.nodes?.[nodeId]) {\n  throw new Error('nodeId is required to fetch archived logs');\n}\ngetContainerLogsFromArtifact(workflow, nodeId, container, grep, archived);","typeGuard":"function hasNode(wf: Workflow, nodeId: string): boolean {\n  return !!wf.status?.nodes && nodeId in wf.status.nodes;\n}","tryCatchPattern":"try {\n  await getLogsFromArtifact(wf, nodeId, container, grep, archived).toPromise();\n} catch (e) {\n  if (e.message.includes('Should specify a node')) {\n    logger.warn('Cannot fetch archived logs without a node ID');\n  }\n}","preventionTips":["Always resolve nodeId from workflow.status.nodes before calling archived log APIs.","Check hasArtifactLogs upstream before switching to the artifact path.","Keep the original node ID in UI state when workflows are archived."],"tags":["ui","logs","archived-workflows"],"backgroundTag":"missing-required-argument","analyzedSha":"35bff19146f5a6ada77468c431f2624bd577e373","analyzedAt":"2026-09-03T19:34:35.908Z","contentChangedAt":"2026-09-03T19:34:35.908Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}