{"record":{"id":"3f73f8584501f987","repo":"openzipkin/zipkin","slug":"key-null-3f73f8","errorCode":null,"errorMessage":"key == null","messagePattern":"key == null","errorType":"validation","errorClass":"NullPointerException","httpStatus":null,"severity":"error","filePath":"zipkin-storage/mysql-v1/src/main/java/zipkin2/storage/mysql/v1/MySQLAutocompleteTags.java","lineNumber":33,"sourceCode":"  final boolean enabled;\n  final LinkedHashSet<String> autocompleteKeys;\n  final Call<List<String>> keysCall;\n\n  MySQLAutocompleteTags(MySQLStorage storage, Schema schema) {\n    this.dataSourceCallFactory = storage.dataSourceCallFactory;\n    this.schema = schema;\n    enabled = storage.searchEnabled && !storage.autocompleteKeys.isEmpty();\n    autocompleteKeys = new LinkedHashSet<>(storage.autocompleteKeys);\n    keysCall = Call.create(storage.autocompleteKeys);\n  }\n\n  @Override public Call<List<String>> getKeys() {\n    if (!enabled) return Call.emptyList();\n    return keysCall.clone();\n  }\n\n  @Override public Call<List<String>> getValues(String key) {\n    if (key == null) throw new NullPointerException(\"key == null\");\n    if (key.isEmpty()) throw new IllegalArgumentException(\"key was empty\");\n    if (!enabled || !autocompleteKeys.contains(key)) return Call.emptyList();\n    return dataSourceCallFactory.create(new SelectAutocompleteValues(schema, key));\n  }\n}\n","sourceCodeStart":15,"sourceCodeEnd":39,"githubUrl":"https://github.com/openzipkin/zipkin/blob/878ce2a1fad54ca941d17fdcf2e1d924b148eb1f/zipkin-storage/mysql-v1/src/main/java/zipkin2/storage/mysql/v1/MySQLAutocompleteTags.java#L15-L39","documentation":"MySQLAutocompleteTags.getValues(key) runs a SelectAutocompleteValues query against the zipkin_annotations table for a configured autocomplete key. The API requires a non-null, non-empty key; null fails fast with NullPointerException('key == null') before any SQL is built. Unlike the Elasticsearch variant, it also requires the key to be in the configured autocompleteKeys set or it returns an empty list.","triggerScenarios":"Calling autocompleteTags().getValues(null) on MySQLStorage, typically by forwarding a missing/unvalidated request parameter straight from an HTTP endpoint.","commonSituations":"Custom REST facades or UIs over MySQLStorage where ?key= is optional and not checked; refactors that introduce null paths; tests passing null.","solutions":["Fix the caller to pass a non-null key; find where the null originates (usually an unchecked request parameter).","Validate input at your API boundary: reject or return empty for missing keys.","Remember the key must also be listed in storage.autocompleteKeys to return data."],"exampleFix":"// before\nString key = request.getParameter(\"key\");\nCall<List<String>> values = storage.autocompleteTags().getValues(key); // NPE when param absent\n\n// after\nString key = request.getParameter(\"key\");\nif (key == null || key.isEmpty()) return Collections.emptyList();\nCall<List<String>> values = storage.autocompleteTags().getValues(key);","handlingStrategy":"validation","validationCode":"if (key == null || key.isEmpty()) {\n  return Collections.emptyList(); // or respond 400 for a required param\n}\nCall<List<String>> values = storage.autocompleteTags().getValues(key);","typeGuard":"static boolean isQueryableKey(String key) {\n  return key != null && !key.isEmpty();\n}","tryCatchPattern":null,"preventionTips":["Validate the key parameter at your HTTP boundary before calling the store.","Remember MySQL only returns values for keys configured in autocompleteKeys.","Add unit tests covering null/empty key paths in any wrapper you build."],"tags":["mysql","autocomplete","null-check","api-contract","storage"],"backgroundTag":null,"analyzedSha":"878ce2a1fad54ca941d17fdcf2e1d924b148eb1f","analyzedAt":"2026-08-14T15:17:09.895Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}