{"record":{"id":"5b5fa4c9764b065f","repo":"conductor-oss/conductor","slug":"agent-card-resolved-from-s-does-not-advertise-a-j","errorCode":null,"errorMessage":"Agent Card resolved from %s does not advertise a JSON-RPC 'url'","messagePattern":"Agent Card resolved from (.+?) does not advertise a JSON-RPC 'url'","errorType":"exception","errorClass":"NonRetryableException","httpStatus":null,"severity":"error","filePath":"ai/src/main/java/org/conductoross/conductor/ai/tasks/worker/A2AWorkers.java","lineNumber":365,"sourceCode":"     */\n    private String resolveRemoteEndpoint(\n            Task task, String configuredUrl, Map<String, String> headers) {\n        String configured = StringUtils.trimToNull(configuredUrl);\n        if (configured == null) {\n            throw new NonRetryableException(\"agentUrl must not be blank\");\n        }\n\n        String snapshottedEndpoint = endpointFromSnapshot(task);\n        if (snapshottedEndpoint != null) {\n            return snapshottedEndpoint;\n        }\n\n        String pathWithoutQuery = StringUtils.substringBefore(configured, \"?\");\n        if (StringUtils.endsWithIgnoreCase(pathWithoutQuery, \".json\")) {\n            AgentCard card = a2aService.getAgentCard(configured, headers);\n            String discoveredEndpoint = card == null ? null : StringUtils.trimToNull(card.getUrl());\n            if (discoveredEndpoint == null) {\n                throw new NonRetryableException(\n                        \"Agent Card resolved from \"\n                                + configured\n                                + \" does not advertise a JSON-RPC 'url'\");\n            }\n            return discoveredEndpoint;\n        }\n        return configured;\n    }\n\n    private String endpointFromSnapshot(Task task) {\n        if (task == null\n                || task.getWorkflowTask() == null\n                || task.getWorkflowTask().getMetadata() == null) {\n            return null;\n        }\n        JsonNode agent =\n                objectMapper.valueToTree(task.getWorkflowTask().getMetadata()).path(\"agent\");\n        if (!A2AService.isA2aAgentType(agent.path(\"agentType\").asText())) {","sourceCodeStart":347,"sourceCodeEnd":383,"githubUrl":"https://github.com/conductor-oss/conductor/blob/cf7c3e4a8adfb158be778ab1ec525323c363cd3a/ai/src/main/java/org/conductoross/conductor/ai/tasks/worker/A2AWorkers.java#L347-L383","documentation":"Thrown by A2AWorkers.resolveRemoteEndpoint when the configured agentUrl points at an Agent Card (path ends in '.json'), the card is successfully fetched via a2aService.getAgentCard, but card.getUrl() is null or blank. The A2A discovery document is required to advertise its JSON-RPC endpoint in a top-level 'url' field; without it Conductor cannot know where to POST JSON-RPC calls. It is a NonRetryableException, so the workflow task fails terminally rather than retrying.","triggerScenarios":"Setting agentUrl to a *.json Agent Card URL whose document has no 'url' key, or whose 'url' value is empty/whitespace. Also triggered when endpointFromSnapshot returns null (no task metadata snapshot) and the live card lacks the url field.","commonSituations":"Hosting an Agent Card JSON at a website URL but forgetting to include the 'url' field; pointing at a partial/mock card; card served by an older/non-compliant A2A agent that omits the JSON-RPC url; SSRF or fetch returning a different document (e.g. an HTML error page parsed as null card).","solutions":["Open the Agent Card JSON at your configured agentUrl and confirm it has a top-level \"url\" field pointing at the JSON-RPC endpoint.","If the card genuinely has no url, point agentUrl directly at the JSON-RPC endpoint URL instead of the .json card.","Add/repair the 'url' field in the served Agent Card document so it advertises the JSON-RPC base URL.","Verify a2aService.getAgentCard reaches the real card (correct headers, no auth redirect to a login HTML page)."],"exampleFix":"// before\n{ \"agentUrl\": \"https://agent.example.com/.well-known/agent.json\" }\n// card missing url -> set the endpoint directly, or fix the card:\n// after (option A: direct endpoint)\n{ \"agentUrl\": \"https://agent.example.com/a2a/jsonrpc\" }\n// after (option B: fix the served card)\n{ \"name\": \"agent\", \"url\": \"https://agent.example.com/a2a/jsonrpc\", \"version\": \"1.0\" }","handlingStrategy":"validation","validationCode":"// Before setting agentUrl to a .json card, fetch and check the url field\nAgentCard card = a2aService.getAgentCard(candidateUrl, headers);\nif (card == null || StringUtils.isBlank(card.getUrl())) {\n    // point agentUrl at the JSON-RPC endpoint directly instead of the card\n    request.setAgentUrl(knownJsonRpcEndpoint);\n} else {\n    request.setAgentUrl(candidateUrl);\n}","typeGuard":null,"tryCatchPattern":"// resolveRemoteEndpoint already wraps NonRetryableException into a terminal task failure;\n// catch at the workflow layer to mark the task and surface the discovery URL.\ntry {\n    String ep = resolveRemoteEndpoint(task, url, headers);\n} catch (NonRetryableException e) {\n    // log configured card URL, fix the card or switch to direct endpoint\n}","preventionTips":["Serve a spec-compliant Agent Card with a non-empty top-level 'url' field.","Prefer pointing agentUrl directly at the JSON-RPC endpoint when you control the agent.","Validate the card document with an A2A spec linter before deploying."],"tags":["a2a","agent-card","configuration","non-retryable"],"backgroundTag":null,"analyzedSha":"cf7c3e4a8adfb158be778ab1ec525323c363cd3a","analyzedAt":"2026-08-14T03:33:19.897Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}