{"record":{"id":"8ff5b11e29f38301","repo":"apache/pulsar","slug":"function-in-trigger-function-has-unidentified-topi","errorCode":null,"errorMessage":"Function in trigger function has unidentified topic","messagePattern":"Function in trigger function has unidentified topic","errorType":"http","errorClass":"RestException","httpStatus":400,"severity":"error","filePath":"pulsar-functions/worker/src/main/java/org/apache/pulsar/functions/worker/rest/api/ComponentImpl.java","lineNumber":1160,"sourceCode":"\n                    .log(\"Function in trigger function has more than 1 input topics @ / / /\");\n            throw new RestException(Status.BAD_REQUEST, \"Function in trigger function has more than 1 input topics\");\n        }\n        boolean topicFound;\n        try {\n            functionMetaData.getFunctionDetails().getSource().getInputSpecs(inputTopicToWrite);\n            topicFound = true;\n        } catch (IllegalArgumentException e) {\n            topicFound = false;\n        }\n        if (functionMetaData.getFunctionDetails().getSource().getInputSpecsCount() == 0\n                || !topicFound) {\n            log.error().attr(\"tenant\", tenant).attr(\"namespace\", namespace).attr(\"componentName\", functionName)\n\n                    .attr(\"topic\", inputTopicToWrite)\n\n                    .log(\"Function in trigger function has unidentified topic @ / / /\");\n            throw new RestException(Status.BAD_REQUEST, \"Function in trigger function has unidentified topic\");\n        }\n        try {\n            worker().getBrokerAdmin().topics().getSubscriptions(inputTopicToWrite);\n        } catch (PulsarAdminException e) {\n            log.error().attr(\"tenant\", tenant).attr(\"namespace\", namespace).attr(\"componentName\", functionName)\n\n                    .exception(e).log(\"Function in trigger function is not ready @ / / /\");\n            throw new RestException(Status.BAD_REQUEST, \"Function in trigger function is not ready\");\n        }\n        String outputTopic = functionMetaData.getFunctionDetails().getSink().getTopic();\n        Reader<byte[]> reader = null;\n        Producer<byte[]> producer = null;\n        try {\n            if (!isEmpty(outputTopic)) {\n                reader = worker().getClient().newReader()\n                        .topic(outputTopic)\n                        .startMessageId(MessageId.latest)\n                        .readerName(worker().getWorkerConfig().getWorkerId() + \"-trigger-\"","sourceCodeStart":1142,"sourceCodeEnd":1178,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-functions/worker/src/main/java/org/apache/pulsar/functions/worker/rest/api/ComponentImpl.java#L1142-L1178","documentation":"After choosing the input topic (from the request or the function's single inputSpec), triggerFunction verifies the topic actually exists in the function's inputSpecs and that the requested topic matches. A null/empty/unresolvable topic, or one not present in inputSpecs, yields HTTP 400 'Function in trigger function has unidentified topic'.","triggerScenarios":"Triggering with a topic query parameter that the function does not declare in its inputSpecs; the function's source has an empty inputSpecs map; the requested topic string doesn't match the fully-resolved inputTopicToWrite.","commonSituations":"Using the short topic name (e.g. 'src-topic') instead of the fully qualified persistent://tenant/namespace/topic; triggering a function whose source was reconfigured after the trigger script was written.","solutions":["Pass the exact fully-qualified topic name that appears in the function's inputSpecs (persistent://tenant/ns/topic).","Omit the topic parameter so the worker uses the function's single declared input topic.","Compare the function config's inputSpecs keys (GET /functions/{tenant}/{namespace}/{functionName}) with your request topic.","Re-upload/reconfigure the function if its source lost its input specs."],"exampleFix":"// before\ncurl -X POST --data-binary 'x' '.../functions/public/default/f?topic=src-topic'\n// after\ncurl -X POST --data-binary 'x' '.../functions/public/default/f?topic=persistent://public/default/src-topic'","handlingStrategy":"validation","validationCode":"static boolean topicDeclared(FunctionConfig cfg, String requested) {\n  return cfg.getSource() != null && cfg.getSource().getInputSpecs() != null\n      && cfg.getSource().getInputSpecs().keySet().stream()\n         .anyMatch(t -> t.equals(requested) || t.endsWith(\"/\" + requested));\n}","typeGuard":null,"tryCatchPattern":"if (!topicDeclared(cfg, topic)) throw new IllegalArgumentException(\"topic not in inputSpecs, expected one of \" + cfg.getSource().getInputSpecs().keySet());\ntriggerFunction(tenant, ns, fn, topic, data, null);","preventionTips":["Always use fully-qualified persistent://tenant/ns/topic names in trigger calls","Read inputSpecs from the function config rather than hardcoding topic strings","Re-validate trigger scripts whenever a function's source config changes"],"tags":["pulsar-functions","bad-request","rest-api","topic"],"backgroundTag":"invalid-topic-name","analyzedSha":"820761864ed8e2a7d2e52dd9763ad2ae117c1395","analyzedAt":"2026-09-06T00:14:20.138Z","contentChangedAt":"2026-09-06T00:14:20.138Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}