{"record":{"id":"9b8ef323fd7e5156","repo":"redis/jedis","slug":"must-have-at-least-one-tag","errorCode":null,"errorMessage":"Must have at least one tag","messagePattern":"Must have at least one tag","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"src/main/java/redis/clients/jedis/search/querybuilder/Values.java","lineNumber":90,"sourceCode":"  public static RangeValue le(double d) {\n    return lt(d).inclusiveMax(true);\n  }\n\n  public static RangeValue le(int d) {\n    return lt(d).inclusiveMax(true);\n  }\n\n  public static RangeValue ge(double d) {\n    return gt(d).inclusiveMin(true);\n  }\n\n  public static RangeValue ge(int d) {\n    return gt(d).inclusiveMin(true);\n  }\n\n  public static Value tags(String... tags) {\n    if (tags.length == 0) {\n      throw new IllegalArgumentException(\"Must have at least one tag\");\n    }\n    StringJoiner sj = new StringJoiner(\" | \");\n    for (String s : tags) {\n      sj.add(s);\n    }\n    return new Value() {\n      @Override\n      public String toString() {\n        return \"{\" + sj.toString() + \"}\";\n      }\n    };\n  }\n}\n","sourceCodeStart":72,"sourceCodeEnd":104,"githubUrl":"https://github.com/redis/jedis/blob/6dac31d4c224fb3257c216f3985340c6f500cdcb/src/main/java/redis/clients/jedis/search/querybuilder/Values.java#L72-L104","documentation":"Values.tags(String... tags) builds a RediSearch tag-filter Value from one or more tag strings. Because a tag filter with zero tags is meaningless in RediSearch query syntax, the method rejects an empty varargs array with IllegalArgumentException(\"Must have at least one tag\").","triggerScenarios":"Calling Values.tags() with no arguments, or passing an empty String[] / empty collection converted to an array (e.g. Values.tags(myList.toArray(new String[0])) where the list is empty).","commonSituations":"Building tag filters from user-selected filter chips or request parameters where the user selected none; dynamic query construction where an empty tags list flows into Values.tags instead of being skipped.","solutions":["Guard the call site: only call Values.tags when the tag array is non-empty.","Skip adding the tag filter node entirely when the list is empty.","If at least one tag is always required by your domain, validate input earlier (e.g. at request parsing) with a clearer message."],"exampleFix":"// before\nQuery.Node n = new QueryBuilder().addFilter(Values.tags(selectedTags.toArray(new String[0])));\n// after\nif (!selectedTags.isEmpty()) {\n  qb.addFilter(Values.tags(selectedTags.toArray(new String[0])));\n}","handlingStrategy":"validation","validationCode":"if (tags == null || tags.length == 0) {\n  throw new IllegalArgumentException(\"At least one tag is required for a tag filter\");\n}\nValue v = Values.tags(tags);","typeGuard":"boolean hasTags(String[] tags) {\n  return tags != null && tags.length > 0;\n}","tryCatchPattern":"try {\n  value = Values.tags(tagArray);\n} catch (IllegalArgumentException e) {\n  log.warn(\"Skipping empty tag filter: {}\", e.getMessage());\n}","preventionTips":["Always check the tag array is non-empty before calling Values.tags.","Skip adding tag filter nodes when the tag list is empty.","Validate tag selection at the API/UI boundary so empty lists never reach query construction."],"tags":["java","search","validation","querybuilder"],"backgroundTag":"empty-required-field","analyzedSha":"6dac31d4c224fb3257c216f3985340c6f500cdcb","analyzedAt":"2026-09-08T04:55:01.204Z","contentChangedAt":"2026-09-08T04:55:01.204Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}