{"record":{"id":"02080b5ec2d40c5b","repo":"elastic/elasticsearch","slug":"expected-to-be-type-string-but-found-type","errorCode":null,"errorMessage":"expected [{}] to be type [String] but found type [{}]","messagePattern":"expected \\[(.+?)\\] to be type \\[String\\] but found type \\[(.+?)\\]","errorType":"validation","errorClass":"PolicyValidationException","httpStatus":null,"severity":"error","filePath":"libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/entitlements/FilesEntitlement.java","lineNumber":208,"sourceCode":"                \"invalid relative directory: \" + baseDir + \", valid values: [config, data, home]\"\n            );\n        };\n    }\n\n    @ExternalEntitlement(parameterNames = { \"paths\" }, esModulesOnly = false)\n    @SuppressWarnings(\"unchecked\")\n    public static FilesEntitlement build(List<Object> paths) {\n        if (paths == null || paths.isEmpty()) {\n            throw new PolicyValidationException(\"must specify at least one path\");\n        }\n        BiFunction<Map<String, Object>, String, String> checkString = (values, key) -> {\n            Object value = values.remove(key);\n            if (value == null) {\n                return null;\n            } else if (value instanceof String str) {\n                return str;\n            }\n            throw new PolicyValidationException(\n                \"expected [\"\n                    + key\n                    + \"] to be type [\"\n                    + String.class.getSimpleName()\n                    + \"] but found type [\"\n                    + value.getClass().getSimpleName()\n                    + \"]\"\n            );\n        };\n        BiFunction<Map<String, Object>, String, Boolean> checkBoolean = (values, key) -> {\n            Object value = values.remove(key);\n            if (value == null) {\n                return null;\n            } else if (value instanceof Boolean bool) {\n                return bool;\n            }\n            throw new PolicyValidationException(\n                \"expected [\"","sourceCodeStart":190,"sourceCodeEnd":226,"githubUrl":"https://github.com/elastic/elasticsearch/blob/db6a809a667c081ca1dc7500389d26975573215f/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/entitlements/FilesEntitlement.java#L190-L226","documentation":"Thrown by the checkString helper in FilesEntitlement.build when one of the string-typed fields (path, relative_path, relative_to, path_setting, basedir_if_relative, mode, platform) is present in the entry map but its value is not a JSON string — e.g. a number, boolean, list, or object.","triggerScenarios":"A files-entitlement entry sets one of the string fields to a non-string JSON value, for example `{ \"path\": 42 }`, `{ \"mode\": true }`, or `{ \"relative_path\": [\"a\",\"b\"] }`.","commonSituations":"Quoting mistake in hand-written JSON (writing `mode: read_write` instead of `\"mode\": \"read_write\"`); YAML-to-JSON conversion where a bare token became a non-string scalar; numeric path id used instead of string; booleans for non-boolean fields.","solutions":["Read the message: it names the field (`key`) and the actual type found.","Quote the value so it is a JSON string.","Re-validate the policy JSON with a linter before encoding."],"exampleFix":"// before\n{ \"path\": /var/log/es, \"mode\": read_write }\n\n// after\n{ \"path\": \"/var/log/es\", \"mode\": \"read_write\" }","handlingStrategy":"type-guard","validationCode":"private static final Set<String> STRING_KEYS = Set.of(\n    \"path\",\"relative_path\",\"relative_to\",\"path_setting\",\"basedir_if_relative\",\"mode\",\"platform\");\npublic static void validateStringFields(Map<String,Object> entry) {\n    for (String k : STRING_KEYS) {\n        Object v = entry.get(k);\n        if (v != null && !(v instanceof String)) {\n            throw new IllegalArgumentException(k + \" must be a string, got \" + v.getClass().getSimpleName());\n        }\n    }\n}","typeGuard":"public static boolean allStringFieldsAreStrings(Map<String,Object> entry) {\n    for (String k : Set.of(\"path\",\"relative_path\",\"relative_to\",\"path_setting\",\"basedir_if_relative\",\"mode\",\"platform\")) {\n        Object v = entry.get(k);\n        if (v != null && !(v instanceof String)) return false;\n    }\n    return true;\n}","tryCatchPattern":null,"preventionTips":["Always quote string literals in policy JSON.","Use a JSON Schema with `type: string` on each string field.","When generating from YAML/JSON, ensure serializers emit strings, not bare scalars."],"tags":["entitlements","files","policy","types","validation"],"analyzedSha":"db6a809a667c081ca1dc7500389d26975573215f","analyzedAt":"2026-08-12T01:39:14.192Z","schemaVersion":2},"datasetVersion":"2026-08-12T12:17:08.281Z"}