{"record":{"id":"ebdefd1b82a5578e","repo":"apache/pulsar","slug":"per-instance-ram-requested-s-for-function-shoul","errorCode":null,"errorMessage":"Per instance ram requested, %s, for function should be positive and a multiple of the granularity, %s","messagePattern":"Per instance ram requested, (.+?), for function should be positive and a multiple of the granularity, (.+?)","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"pulsar-functions/runtime/src/main/java/org/apache/pulsar/functions/runtime/kubernetes/KubernetesRuntimeFactory.java","lineNumber":521,"sourceCode":"                // convert cpus to milli-cores to avoid loss of precision\n                long grnCpuMillis = Math.round(baseMillis * grnCpu);\n                if (grnCpuMillis > 0) {\n                    long cpuMillis = Math.round(baseMillis * functionDetails.getResources().getCpu());\n                    if (cpuMillis == 0 || cpuMillis % grnCpuMillis != 0) {\n                        throw new IllegalArgumentException(\n                                String.format(\"Per instance cpu requested, %s, for function should be positive and a \"\n                                                + \"multiple of the granularity, %s\",\n                                        functionDetails.getResources().getCpu(), grnCpu));\n                    }\n                    if (functionInstanceResourceChangeInLockStep) {\n                        multiples = cpuMillis / grnCpuMillis;\n                    }\n                }\n            }\n            if (grnRam != null && grnRam > 0) {\n                if (functionDetails.getResources().getRam() == 0\n                        || functionDetails.getResources().getRam() % grnRam != 0) {\n                    throw new IllegalArgumentException(\n                            String.format(\"Per instance ram requested, %s, \"\n                                            + \"for function should be positive and a multiple of the granularity, %s\",\n                                    functionDetails.getResources().getRam(), grnRam));\n                }\n                if (functionInstanceResourceChangeInLockStep && multiples > 0) {\n                    long ramMultiples = functionDetails.getResources().getRam() / grnRam;\n                    if (multiples != ramMultiples) {\n                        throw new IllegalArgumentException(\n                                String.format(\"Per instance cpu requested, %s, ram requested, %s,\"\n                                                + \" for function should be positive and the same multiple of the \"\n                                                + \"granularity, cpu, %s, ram, %s\",\n                                        functionDetails.getResources().getCpu(),\n                                        functionDetails.getResources().getRam(), grnCpu, grnRam));\n                    }\n                }\n            }\n        }\n    }","sourceCodeStart":503,"sourceCodeEnd":539,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-functions/runtime/src/main/java/org/apache/pulsar/functions/runtime/kubernetes/KubernetesRuntimeFactory.java#L503-L539","documentation":"In the same admission check, KubernetesRuntimeFactory validates that the function's per-instance RAM is positive and an exact multiple of the configured RAM granularity (grnRam). If getResources().getRam() is 0 or not divisible by grnRam, doAdmissionChecks rejects the function with this IllegalArgumentException.","triggerScenarios":"Submitting a function to the Kubernetes runtime when functionInstanceResourceGranularity defines a RAM granularity and FunctionDetails.getResources().getRam() is 0, negative, or not a whole multiple of grnRam (bytes).","commonSituations":"RAM left unset (0) while granularity is configured; RAM specified in MB/GB by hand and not landing on the granularity boundary (e.g. ram=1500MB with granularity 1GB = 1073741824 bytes); copying function configs between clusters with different granularity settings.","solutions":["Set resources.ram to a positive value that is an exact whole multiple of the configured RAM granularity in bytes.","Round the requested RAM up to the next granularity step (e.g. granularity 1GB -> use 2147483648 for 2GB).","Unset functionInstanceResourceGranularity in the worker config if per-cluster granularity enforcement is not wanted.","If functionInstanceResourceChangeInLockStep is on, make sure the ram multiple matches the cpu multiple."],"exampleFix":"// before (granularity = 1073741824 bytes)\nresources:\n  ram: 1500MB\n// after\nresources:\n  ram: 2147483648  # 2GB, exact multiple","handlingStrategy":"validation","validationCode":"long grnRam = configuredRamGranularityBytes; // from worker config\nlong ram = functionDetails.getResources().getRam();\nif (ram <= 0 || ram % grnRam != 0) {\n    throw new IllegalArgumentException(\"ram must be positive and a multiple of \" + grnRam + \" bytes\");\n}","typeGuard":"boolean isValidRam(Long ramBytes, long granularityBytes) {\n    return ramBytes != null && ramBytes > 0 && granularityBytes > 0 && ramBytes % granularityBytes == 0;\n}","tryCatchPattern":null,"preventionTips":["Express ram in bytes and round up to the nearest granularity step.","Check the cluster's RAM granularity before migrating functions between clusters.","Pair ram multiples with cpu multiples if lock-step resource changes are enabled."],"tags":["pulsar-functions","kubernetes","resource-validation","configuration"],"backgroundTag":"resource-granularity-violation","analyzedSha":"820761864ed8e2a7d2e52dd9763ad2ae117c1395","analyzedAt":"2026-09-06T00:14:20.138Z","contentChangedAt":"2026-09-06T00:14:20.138Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}