xai-org/x-algorithm · error · SemanticCheckFailure
Contains expects input of String, Map, Set or Collection typ
Error message
Contains expects input of String, Map, Set or Collection types but %s received
What it means
Contains() only accepts a first argument whose static return type is String, Set, Collection, Map, or a generic Object. Any other typeBase (e.g. Long, Boolean, StructTuple) fails semantic checking with this message. Note that a non-Set Collection is automatically coerced via ToSet before containment is checked.
Source
Thrown at botmaker/src/java/com/twitter/botmaker/function/collection/Contains.java:55
private static final Signature SIGNATURE = new Signature(
ImmutableList.of(
Type.OBJECT,
Type.OBJECT),
Type.BOOLEAN
);
public Contains(String exprText, ImmutableList<ASTNode> children) throws SemanticCheckFailure {
super(exprText, validateASTNodesAndModifyType(children));
}
private static ImmutableList<ASTNode> validateASTNodesAndModifyType(
ImmutableList<ASTNode> children) throws SemanticCheckFailure {
Class<?> typeBase = children.get(0).getReturnType().typeBase;
if (!Object.class.equals(typeBase)
&& !String.class.equals(typeBase)
&& !Collection.class.isAssignableFrom(typeBase)
&& !Map.class.isAssignableFrom(typeBase)) {
throw new SemanticCheckFailure(String.format(
"Contains expects input of String, Map, Set or Collection types but %s received",
typeBase.getName()));
}
if (Collection.class.isAssignableFrom(typeBase) && !Set.class.isAssignableFrom(typeBase)) {
ASTNode setifiedCollection = new ToSet("ToSet", ImmutableList.of(children.get(0)));
return ImmutableList.of(setifiedCollection, children.get(1));
}
return children;
}
@Override
public Signature getSignature() {
return SIGNATURE;
}
@Override
protected CacheLevel getCacheLevel() {View on GitHub (pinned to 24c60942c5)
Solutions
- Change the first argument to a String, Set, Collection or Map expression
- If the value might be anything, cast/annotate it as Object so the generic path applies
- Wrap the value in a coercion function that produces a collection (e.g. Split for strings)
Example fix
// before Contains(Count(items), 3) // after Contains(items, 3) // or use the collection directly
Defensive patterns
Strategy: type-guard
Validate before calling
// rule-language: coerce unknown input before Contains Contains(ToString(maybeAny), "needle")
Type guard
// host code: check the child's static type before building Contains
Class<?> base = child.getReturnType().typeBase;
boolean ok = Object.class.equals(base) || String.class.equals(base)
|| Collection.class.isAssignableFrom(base) || Map.class.isAssignableFrom(base); Prevention
- Keep Contains' first argument a String/Set/Collection/Map expression
- Remember non-Set Collections are auto-coerced via ToSet
- Re-check argument types after refactoring pipelines
When it happens
Trigger: Passing Contains(someLong, x), Contains(true, x), or Contains(structTuple, x). Also passing a typed value whose inferred typeBase is not in the allowed set.
Common situations: Chaining Contains after a function that returns a scalar (Count, Size), or after refactoring a pipeline so the first argument's type changed from a collection to a scalar.
Related errors
- Copy function only supports Map or StructTuple.
- StructTuple field %s expects type %s, but %s received.
- Count expects input of String, Map or Collection types but %
- Type %s does not support index accessor
- expecting the input to be of String or List type but receive
AI-assisted analysis of xai-org/x-algorithm@24c60942c5 (2026-08-28).
Data as JSON: /api/errors/82dc12915cb89642.
Report an issue: GitHub.