{"record":{"id":"d60536419ae87153","repo":"apache/druid","slug":"an-external-http-table-with-a-uri-must-also-provid","errorCode":null,"errorMessage":"An external HTTP table with a URI must also provide the corresponding format","messagePattern":"An external HTTP table with a URI must also provide the corresponding format","errorType":"validation","errorClass":"IAE","httpStatus":null,"severity":"error","filePath":"server/src/main/java/org/apache/druid/catalog/model/table/HttpInputSourceDefn.java","lineNumber":155,"sourceCode":"    final String uriTemplate = table.resolvedTable().stringProperty(URI_TEMPLATE_PROPERTY);\n    final boolean hasTemplate = uriTemplate != null;\n    final boolean hasFormat = table.inputFormatMap != null;\n    final boolean hasColumns = !CollectionUtils.isNullOrEmpty(table.resolvedTable().spec().columns());\n\n    if (!hasUri && !hasTemplate) {\n      throw new IAE(\n          \"External HTTP tables must provide either a URI or a %s property\",\n          URI_TEMPLATE_PROPERTY\n      );\n    }\n    if (hasUri && hasTemplate) {\n      throw new IAE(\n          \"External HTTP tables must provide only one of a URI or a %s property\",\n          URI_TEMPLATE_PROPERTY\n      );\n    }\n    if (hasUri && !hasFormat) {\n      throw new IAE(\n          \"An external HTTP table with a URI must also provide the corresponding format\"\n      );\n    }\n    if (hasUri && !hasColumns) {\n      throw new IAE(\n          \"An external HTTP table with a URI must also provide the corresponding columns\"\n      );\n    }\n    if (hasTemplate) {\n\n      // Verify the template\n      templateMatcher(uriTemplate);\n\n      // Patch in a dummy URI so that validation of the rest of the fields\n      // will pass.\n      try {\n        sourceMap.put(\n            URIS_FIELD,","sourceCodeStart":137,"sourceCodeEnd":173,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/server/src/main/java/org/apache/druid/catalog/model/table/HttpInputSourceDefn.java#L137-L173","documentation":"Thrown by HttpInputSourceDefn.validate when an external HTTP table declares a URI but provides no input format. With a concrete URI the table must also know how to parse the bytes fetched from it, which requires a format (and format factory) on the table.","triggerScenarios":"Validating a table whose HTTP input source includes 'uris' but whose resolved table has inputFormatMap == null.","commonSituations":"Hand-writing a table spec and adding the URI but forgetting the 'format' property; a builder that sets the source before the format is attached and validation runs early.","solutions":["Add the format property to the table, e.g. {\"format\": {\"type\": \"json\"}} or the catalog's format argument","Use the catalog table builder API to set format together with the URI","Re-run validation after adding the format to confirm no further gaps"],"exampleFix":"// before\n{\"type\": \"http\", \"uris\": [\"https://a.com/d.json\"]} // no format\n// after\n{\"type\": \"http\", \"uris\": [\"https://a.com/d.json\"]} + format: {\"type\": \"json\"}","handlingStrategy":"validation","validationCode":"if (uris != null && uris.size() > 0 && format == null) { throw new IAE(\"format required with URI\"); }","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Set format at the same time as the URI in builders","Use templates that pair URI with format"],"tags":["catalog","http","validation"],"backgroundTag":"missing-required-config-field","analyzedSha":"9b90983fd291f26935af934383ce360473179e4d","analyzedAt":"2026-09-07T13:32:30.957Z","contentChangedAt":"2026-09-07T13:32:30.957Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}