{"record":{"id":"d83c0f5ab2f101df","repo":"thingsboard/thingsboard","slug":"item-not-found","errorCode":"ITEM_NOT_FOUND","errorMessage":"Alarm rule not found","messagePattern":"Alarm rule not found","errorType":"http","errorClass":"ThingsboardException","httpStatus":404,"severity":"error","filePath":"application/src/main/java/org/thingsboard/server/controller/AlarmRuleController.java","lineNumber":254,"sourceCode":"                .orElse(null);\n    }\n\n    @ApiOperation(value = \"Test alarm rule TBEL expression (testAlarmRuleScript)\",\n            notes = TEST_SCRIPT_EXPRESSION + TENANT_AUTHORITY_PARAGRAPH)\n    @PreAuthorize(\"hasAuthority('TENANT_ADMIN')\")\n    @PostMapping(\"/alarm/rule/testScript\")\n    public JsonNode testAlarmRuleScript(\n            @io.swagger.v3.oas.annotations.parameters.RequestBody(description = \"Test alarm rule TBEL condition expression. The expression must return a boolean value.\")\n            @RequestBody JsonNode inputParams) throws ThingsboardException {\n        checkParameter(\"expression\", inputParams.has(\"expression\") ? inputParams.get(\"expression\").asText() : null);\n        return tbCalculatedFieldService.executeTestScript(getTenantId(), inputParams);\n    }\n\n    private CalculatedField checkAlarmRule(CalculatedFieldId calculatedFieldId) throws ThingsboardException {\n        CalculatedField calculatedField = tbCalculatedFieldService.findById(calculatedFieldId, getCurrentUser());\n        checkNotNull(calculatedField);\n        if (calculatedField.getType() != CalculatedFieldType.ALARM) {\n            throw new ThingsboardException(\"Alarm rule not found\", ThingsboardErrorCode.ITEM_NOT_FOUND);\n        }\n        return calculatedField;\n    }\n\n}\n","sourceCodeStart":236,"sourceCodeEnd":260,"githubUrl":"https://github.com/thingsboard/thingsboard/blob/45c30e83fa57356840d5f25d894002d94222d524/application/src/main/java/org/thingsboard/server/controller/AlarmRuleController.java#L236-L260","documentation":"Thrown by AlarmRuleController helper checkAlarmRule when the referenced CalculatedField exists but its type is not CalculatedFieldType.ALARM. 'Alarm rules' in this version are implemented as calculated fields of type ALARM; passing the ID of a regular (non-alarm) calculated field resolves the entity but fails the type check and reports ITEM_NOT_FOUND.","triggerScenarios":"Calling an alarm-rule endpoint (e.g. GET /api/alarm/rule/{id} or testScript-related flows that go through checkAlarmRule) with the UUID of a calculated field created under /api/calculatedField whose type is SCRIPT or simple.","commonSituations":"UI state pointing at a stale ID after an alarm rule was deleted and its ID reused by a normal calculated field; scripts mixing IDs from the calculated-field API and the alarm-rule API; importing an entity where the rule reference was remapped incorrectly.","solutions":["Verify the ID with GET /api/calculatedField/{id} and check that type == 'ALARM'; if not, obtain the correct alarm rule ID from the alarm-rules listing endpoint.","If the alarm rule was deleted, recreate it and update the referencing client/dashboard.","Check for ID copy-paste errors between calculated fields and alarm rules in configs or imports."],"exampleFix":"// before\nGET /api/alarm/rule/6f8f1a00-... // ID of a plain calculated field -> ITEM_NOT_FOUND \"Alarm rule not found\"\n\n// after\n// list alarm rules and use one whose type is ALARM:\nGET /api/alarm/rules?page=0&pageSize=10\nGET /api/alarm/rule/<alarmRuleId-with-type-ALARM>","handlingStrategy":"validation","validationCode":"// Resolve the ID through the calculated-field API and check the type first:\nconst cf = await tb.get(`/api/calculatedField/${calculatedFieldId}`);\nif (cf.data.type !== 'ALARM') {\n  throw new Error(`${calculatedFieldId} is a '${cf.data.type}' calculated field, not an alarm rule`);\n}","typeGuard":"interface CalculatedFieldLike { id?: {id: string}; type?: string }\nfunction isAlarmRule(cf: CalculatedFieldLike | null | undefined): cf is { id: {id: string}; type: 'ALARM' } {\n  return !!cf && cf.type === 'ALARM' && !!cf.id?.id;\n}","tryCatchPattern":"try { return await tb.get(`/api/alarm/rule/${id}`); }\ncatch (e) {\n  if (e.response?.status === 404 && /Alarm rule not found/.test(e.response.data.message)) {\n    return await listAlarmRules(); // re-resolve from the authoritative list\n  }\n  throw e;\n}","preventionTips":["Keep alarm-rule IDs and calculated-field IDs in separate, clearly named config fields.","After deleting a rule, immediately purge references in dashboards/scripts.","Validate stored IDs against a fresh list after environment imports or migrations."],"tags":["alarm-rule","calculated-field","entity-type-mismatch","not-found"],"backgroundTag":null,"analyzedSha":"45c30e83fa57356840d5f25d894002d94222d524","analyzedAt":"2026-08-14T11:45:36.599Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}