{"record":{"id":"a922e05c62098b00","repo":"apache/druid","slug":"a-table-definition-must-include-a-table-spec","errorCode":null,"errorMessage":"A table definition must include a table spec.","messagePattern":"A table definition must include a table spec\\.","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"server/src/main/java/org/apache/druid/catalog/model/TableMetadata.java","lineNumber":270,"sourceCode":"  public TableSpec spec()\n  {\n    return spec;\n  }\n\n  /**\n   * Syntactic validation of a table object. Validates only that which\n   * can be checked from this table object.\n   */\n  public void validate()\n  {\n    if (Strings.isNullOrEmpty(id.schema())) {\n      throw new IAE(\"Database schema is required\");\n    }\n    if (Strings.isNullOrEmpty(id.name())) {\n      throw new IAE(\"Table name is required\");\n    }\n    if (spec == null) {\n      throw new IAE(\"A table definition must include a table spec.\");\n    }\n  }\n\n  @Override\n  public String toString()\n  {\n    return CatalogUtils.toString(this);\n  }\n\n  @Override\n  public boolean equals(Object o)\n  {\n    if (o == this) {\n      return true;\n    }\n    if (o == null || o.getClass() != getClass()) {\n      return false;\n    }","sourceCodeStart":252,"sourceCodeEnd":288,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/server/src/main/java/org/apache/druid/catalog/model/TableMetadata.java#L252-L288","documentation":"A TableMetadata carries the table's TableSpec (properties and columns). validate() requires this spec to be present; a null spec means the table object has no definition content, so validation throws IAE after the id checks pass.","triggerScenarios":"Calling TableMetadata.validate() where the spec field is null — metadata created without a spec, or deserialization of a metadata record that lacked the spec object.","commonSituations":"Creating TableMetadata placeholders before the spec is fetched; API payloads that return metadata rows without the embedded spec JSON; accidental null passed to the constructor.","solutions":["Attach a valid TableSpec to the TableMetadata before validating","Check why the spec was not deserialized (missing JSON field, wrong payload)","If the metadata is intentionally a stub, skip validate() until a spec is available"],"exampleFix":"// before\nTableMetadata md = new TableMetadata(id, null);\nmd.validate();\n// after\nTableMetadata md = new TableMetadata(id, new TableSpec(\"datasource\", props, columns));\nmd.validate();","handlingStrategy":"type-guard","validationCode":"if (md == null || md.spec() == null) {\n  throw new IllegalArgumentException(\"table metadata requires a spec\");\n}","typeGuard":"boolean hasSpec(TableMetadata md) {\n  return md != null && md.spec() != null;\n}","tryCatchPattern":"try { md.validate(); } catch (IllegalArgumentException e) { if (e.getMessage().contains(\"must include a table spec\")) { /* fetch or build the spec */ } else { throw e; } }","preventionTips":["Make spec a required constructor argument where possible","Check API payloads always include the spec object","Only validate fully-assembled TableMetadata objects"],"tags":["validation","catalog","null-value"],"backgroundTag":"missing-required-argument","analyzedSha":"9b90983fd291f26935af934383ce360473179e4d","analyzedAt":"2026-09-07T13:32:30.957Z","contentChangedAt":"2026-09-07T13:32:30.957Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}