{"record":{"id":"a09e208f8edb6f55","repo":"thingsboard/thingsboard","slug":"more-than-one-related-entity-is-not-supported-for","errorCode":null,"errorMessage":"More than one related entity is not supported for relation direction 'TO'. Found: {}.","messagePattern":"More than one related entity is not supported for relation direction 'TO'\\. Found: (.+?)\\.","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"application/src/main/java/org/thingsboard/server/service/cf/ctx/state/aggregation/RelatedEntitiesAggregationCalculatedFieldState.java","lineNumber":323,"sourceCode":"            if (argumentEntry == null || argumentEntry.isEmpty()) {\n                return ReadinessStatus.notReady(MISSING_AGGREGATION_ENTITIES_ERROR);\n            }\n            if (argumentEntry instanceof RelatedEntitiesArgumentEntry relatedEntitiesArgumentEntry) {\n                try {\n                    checkConstraintByDirection(relatedEntitiesArgumentEntry);\n                } catch (Exception e) {\n                    return ReadinessStatus.notReady(e.getMessage());\n                }\n            }\n        }\n        return ReadinessStatus.READY;\n    }\n\n    public void checkConstraintByDirection(RelatedEntitiesArgumentEntry relatedEntitiesArgumentEntry) {\n        if (ctx.getCalculatedField().getConfiguration() instanceof RelatedEntitiesAggregationCalculatedFieldConfiguration config) {\n            if (EntitySearchDirection.TO == config.getRelation().direction()) {\n                if (relatedEntitiesArgumentEntry.getEntityInputs().size() > 1) {\n                    throw new IllegalArgumentException(\"More than one related entity is not supported for relation direction 'TO'. Found: \" + relatedEntitiesArgumentEntry.getEntityInputs().size() + \".\");\n                }\n            }\n        }\n    }\n\n}\n","sourceCodeStart":305,"sourceCodeEnd":330,"githubUrl":"https://github.com/thingsboard/thingsboard/blob/45c30e83fa57356840d5f25d894002d94222d524/application/src/main/java/org/thingsboard/server/service/cf/ctx/state/aggregation/RelatedEntitiesAggregationCalculatedFieldState.java#L305-L330","documentation":"RelatedEntitiesAggregationCalculatedFieldState.checkConstraintByDirection throws when a related-entities aggregation calculated field is configured with relation direction TO and the argument's entity inputs contain more than one entity. Direction TO (pointing at the current entity) is only defined for exactly one source entity, so >1 is ambiguous.","triggerScenarios":"Related-entities aggregation field with relation.direction = TO where the relation query resolves multiple entities feeding one argument — e.g. several devices all having 'Manages' relations TO the same asset being calculated.","commonSituations":"Relation graph has multiple inbound relations of the chosen type; direction was left as TO when FROM was intended; test data created duplicate relations.","solutions":["Switch the relation direction to FROM if the calculation should fan out over many related entities.","If TO is correct, ensure exactly one inbound relation of that type exists — delete or tighten duplicates/extra relations.","Use a more specific relation type so only one entity matches.","Add a guard in onboarding so only a single TO-relation per entity/type is created."],"exampleFix":"// config before\n\"relation\": { \"type\": \"Manages\", \"direction\": \"TO\" }\n\n// config after (fan-out over related devices)\n\"relation\": { \"type\": \"Manages\", \"direction\": \"FROM\" }","handlingStrategy":"validation","validationCode":"// Pre-check: TO direction allows exactly one entity input\nif (EntitySearchDirection.TO == config.getRelation().direction()\n        && candidateEntities.size() > 1) {\n    throw new IllegalStateException(\"Direction TO resolves \" + candidateEntities.size()\n        + \" entities; only one is allowed — use FROM or narrow the relation type\");\n}","typeGuard":null,"tryCatchPattern":"try { state.checkConstraintByDirection(entry); }\ncatch (IllegalArgumentException e) {\n    if (e.getMessage().contains(\"not supported for relation direction 'TO'\")) {\n        // prompt: change direction to FROM or reduce matching relations to one\n    } else throw e;\n}","preventionTips":["Model inbound relations as unique (one source per type) when planning TO-direction calculations.","Lint relation graphs periodically for multi-entity inbound matches on aggregation fields."],"tags":["thingsboard","calculated-fields","relations","aggregation","direction"],"backgroundTag":null,"analyzedSha":"45c30e83fa57356840d5f25d894002d94222d524","analyzedAt":"2026-08-14T11:45:36.599Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}