{"record":{"id":"bad133222407032c","repo":"pinpoint-apm/pinpoint","slug":"invalid-from-usernode","errorCode":null,"errorMessage":"Invalid from UserNode:{}","messagePattern":"Invalid from UserNode:(.+?)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"web/src/main/java/com/navercorp/pinpoint/web/applicationmap/appender/histogram/DefaultNodeHistogramFactory.java","lineNumber":119,"sourceCode":"\n            AgentTimeHistogramBuilder agentTimeBuilder = new AgentTimeHistogramBuilder(terminalApplication, range);\n            AgentTimeHistogram agentTimeHistogram = agentTimeBuilder.buildTarget(mergeSource);\n            nodeBuilder.setAgentTimeHistogram(agentTimeHistogram);\n        }\n\n        return nodeBuilder.build();\n    }\n\n    @Override\n    public NodeHistogram createUserNodeHistogram(Application userApplication, Range range, LinkList linkList) {\n        // for User nodes, find its source link and create the histogram\n        final List<Link> fromLink = linkList.findFromLink(userApplication);\n        if (fromLink.isEmpty()) {\n            logger.warn(\"from UserNode not found:{}\", userApplication);\n            return createEmptyNodeHistogram(userApplication, range);\n        } else if (fromLink.size() > 1) {\n            // log and use first(0) link.\n            logger.warn(\"Invalid from UserNode:{}\", linkList.getLinkList());\n        }\n        final Link sourceLink = fromLink.get(0);\n\n        final NodeHistogram.Builder builder = NodeHistogram.newBuilder(userApplication, range);\n        builder.setApplicationHistogram(sourceLink.getHistogram());\n\n        ApplicationTimeHistogram histogramData = sourceLink.getTargetApplicationTimeSeriesHistogramData();\n        builder.setApplicationTimeHistogram(histogramData);\n        return builder.build();\n    }\n\n    @Override\n    public NodeHistogram createQueueNodeHistogram(Application queueApplication, Range range, LinkList linkList) {\n        final List<Link> toLinkList = linkList.findToLink(queueApplication);\n        if (toLinkList.isEmpty()) {\n            return NodeHistogram.empty(queueApplication, range);\n        }\n","sourceCodeStart":101,"sourceCodeEnd":137,"githubUrl":"https://github.com/pinpoint-apm/pinpoint/blob/744c3d3075e595656abb1ae331ad2c0e4c9eb996/web/src/main/java/com/navercorp/pinpoint/web/applicationmap/appender/histogram/DefaultNodeHistogramFactory.java#L101-L137","documentation":"Also in DefaultNodeHistogramFactory.createUserNodeHistogram: when findFromLink returns more than one incoming link for the User node, the factory logs 'Invalid from UserNode' with the whole link list. The code deliberately continues, using the first link (index 0) as the source for the histogram, so the resulting histogram may reflect an arbitrary one of several user links.","triggerScenarios":"Calling createUserNodeHistogram(userApplication, range, linkList) when the LinkList contains two or more links whose destination is the same user Application — typically duplicated USER->APP links built by overlapping map-builder runs or merged map data.","commonSituations":"Merging application maps from multiple emitters that each created their own user link; a bug or retry in the link appender duplicating the user->app link; front-end requesting a map for a range where the user link was rebuilt and both old/new links remain in the LinkList.","solutions":["Deduplicate USER->APP links when building/merging the LinkList so each user application has exactly one from-link.","Check the link-merging code path (LinkList/MapLinks) for conditions that append duplicate user links.","Log/inspect linkList contents shown in the warning to identify which builder produced the extra link.","If determinism matters, explicitly select the desired source link rather than relying on get(0)."],"exampleFix":"// before\nfinal Link sourceLink = fromLink.get(0);\n// after\nfinal Link sourceLink = fromLink.stream()\n        .min(Comparator.comparing(Link::getLinkKey))\n        .orElseThrow(() -> new IllegalStateException(\"no user link for \" + userApplication));","handlingStrategy":"validation","validationCode":"// ensure exactly one from-link exists before calling the factory\nList<Link> fromLinks = linkList.findFromLink(userApplication);\nif (fromLinks.size() > 1) {\n    logger.warn(\"duplicate user links for {}: {}\", userApplication, fromLinks.size());\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Deduplicate links when merging application maps.","Avoid combining overlapping time-range snapshots in one LinkList.","Assert single-link invariant in link-list construction tests.","Do not rely on get(0) ordering when multiple links exist."],"tags":["application-map","duplicate-links","apm"],"backgroundTag":"invalid-state-transition","analyzedSha":"744c3d3075e595656abb1ae331ad2c0e4c9eb996","analyzedAt":"2026-09-07T18:48:45.289Z","contentChangedAt":"2026-09-07T18:48:45.289Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}