{"record":{"id":"f14c860a1e44b4d6","repo":"apache/pulsar","slug":"e-getmessage-f14c86","errorCode":null,"errorMessage":"e.getMessage()","messagePattern":"e\\.getMessage\\(\\)","errorType":"http","errorClass":"RestException","httpStatus":400,"severity":"error","filePath":"pulsar-functions/worker/src/main/java/org/apache/pulsar/functions/worker/rest/api/FunctionsImplV2.java","lineNumber":111,"sourceCode":"        for (FunctionStatus.FunctionInstanceStatus instanceStatus : functionStatus.instances) {\n            toProto(functionStatusList.addFunctionStatus(),\n                    instanceStatus.getStatus(),\n                    String.valueOf(instanceStatus.getInstanceId()));\n        }\n        String jsonResponse = functionStatusList.toJson();\n        return Response.status(Response.Status.OK).entity(jsonResponse).build();\n    }\n\n    @Override\n    public Response registerFunction(String tenant, String namespace, String functionName, InputStream\n            uploadedInputStream, FormDataContentDisposition fileDetail, String functionPkgUrl, String\n                                             functionDetailsJson, AuthenticationParameters authParams) {\n\n        FunctionDetails functionDetails = new FunctionDetails();\n        try {\n            functionDetails.parseFromJson(functionDetailsJson);\n        } catch (Exception e) {\n            throw new RestException(Response.Status.BAD_REQUEST, e.getMessage());\n        }\n        FunctionConfig functionConfig = FunctionConfigUtils.convertFromDetails(functionDetails);\n\n        delegate.registerFunction(tenant, namespace, functionName, uploadedInputStream, fileDetail,\n                functionPkgUrl, functionConfig, authParams);\n        return Response.ok().build();\n    }\n\n    @Override\n    public Response updateFunction(String tenant, String namespace, String functionName,\n                                   InputStream uploadedInputStream, FormDataContentDisposition fileDetail,\n                                   String functionPkgUrl, String functionDetailsJson,\n                                   AuthenticationParameters authParams) {\n\n        FunctionDetails functionDetails = new FunctionDetails();\n        try {\n            functionDetails.parseFromJson(functionDetailsJson);\n        } catch (Exception e) {","sourceCodeStart":93,"sourceCodeEnd":129,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-functions/worker/src/main/java/org/apache/pulsar/functions/worker/rest/api/FunctionsImplV2.java#L93-L129","documentation":"HTTP 400 thrown by FunctionsImplV2.registerFunction when the submitted functionDetailsJson cannot be parsed into a FunctionDetails proto JSON. Any parse/validation exception (bad JSON syntax, missing required fields like className/inputs, invalid enum values) is caught and its message returned as the 400 body.","triggerScenarios":"POSTing to the V2 functions registration endpoint with a functionDetails field that is not valid JSON, or JSON missing required FunctionDetails fields (tenant, namespace, name, className, inputs, output, runtime), or an unknown runtime/enum string.","commonSituations":"Hand-rolled JSON payloads with typo'd field names (e.g. 'classname' vs 'className'); passing the whole FunctionConfig JSON (source/sink shape) where FunctionDetails proto JSON is expected; double-encoding the JSON string; schema drift after upgrading Pulsar so previously-valid fields are rejected.","solutions":["Validate the JSON against FunctionDetails proto format: required top-level fields and correct enum spellings (e.g. RuntimeType JAVA).","Use FunctionDetails::toJson (or FunctionConfigUtils.convertToDetails on a FunctionConfig) client-side to generate the payload instead of hand-writing JSON.","Read the 400 message body — protobuf JSON parse errors usually name the offending field or token."],"exampleFix":"// before\nString details = \"{\\\"classname\\\": \\\"com.ex.Fn\\\"}\"; // typo'd field\n// after\nFunctionDetails details = FunctionConfigUtils.convertToDetails(functionConfig);\nregisterFunction(tenant, ns, name, stream, fileDetail, pkgUrl, details.toJson(), authParams);","handlingStrategy":"validation","validationCode":"try {\n    FunctionDetails details = FunctionDetails.parseFromJson(functionDetailsJson); // dry-run parse client-side\n} catch (Exception e) {\n    throw new IllegalArgumentException(\"invalid functionDetails JSON: \" + e.getMessage());\n}","typeGuard":"function isJsonObject(s) {\n  try { return JSON.parse(s) !== null && typeof JSON.parse(s) === 'object'; } catch { return false; }\n}","tryCatchPattern":"try {\n    admin.registerFunctionV2(..., functionDetailsJson);\n} catch (ApiException e) {\n    if (e.code() == 400) {\n        // log e.body(): names the JSON parse/validation failure\n    }\n}","preventionTips":["Generate functionDetailsJson programmatically via FunctionDetails.toJson rather than hand-writing JSON.","Keep required fields (className, inputs, output, runtime) present and enum values correctly spelled.","Round-trip parse the JSON client-side before sending to catch schema drift after upgrades."],"tags":["rest","bad-request","json","protobuf","pulsar-functions"],"backgroundTag":"schema-validation-failed","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"}