{"record":{"id":"b5b38c13ef077b6e","repo":"apache/druid","slug":"failed-to-deserialize-a-db-object","errorCode":null,"errorMessage":"Failed to deserialize a DB object","messagePattern":"Failed to deserialize a DB object","errorType":"exception","errorClass":"ISE","httpStatus":null,"severity":"error","filePath":"extensions-core/druid-catalog/src/main/java/org/apache/druid/catalog/storage/sql/SQLCatalogManager.java","lineNumber":747,"sourceCode":"  private NotFoundException tableNotFound(TableId id)\n  {\n    return new NotFoundException(\n        \"Table %s: not found\",\n        id.sqlName()\n    );\n  }\n\n  /**\n   * Deserialize an object from an array of bytes. Use when the object is\n   * known deserializable so that the Jackson exception can be suppressed.\n   */\n  private static <T> T fromBytes(ObjectMapper jsonMapper, byte[] bytes, TypeReference<T> typeRef)\n  {\n    try {\n      return jsonMapper.readValue(bytes, typeRef);\n    }\n    catch (IOException e) {\n      throw new ISE(e, \"Failed to deserialize a DB object\");\n    }\n  }\n\n  private static TableSpec tableSpecFromBytes(\n      final ObjectMapper jsonMapper,\n      final String type,\n      final byte[] properties,\n      final byte[] columns\n  )\n  {\n    return new TableSpec(\n        type,\n        properties == null ? null : propertiesFromBytes(jsonMapper, properties),\n        columns == null ? null : columnsFromBytes(jsonMapper, columns)\n    );\n  }\n\n  private static final TypeReference<Map<String, Object>> PROPERTIES_TYPE_REF = new TypeReference<>() {};","sourceCodeStart":729,"sourceCodeEnd":765,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/extensions-core/druid-catalog/src/main/java/org/apache/druid/catalog/storage/sql/SQLCatalogManager.java#L729-L765","documentation":"fromBytes deserializes a BLOB column (properties/columns JSON) from the catalog tables into Java objects using Jackson. If the stored bytes are not valid JSON or don't match the expected TypeReference, it wraps the IOException in this ISE. It almost always means corrupt or incompatible data in the metadata DB.","triggerScenarios":"Any read path (readTable, listTableNames, etc.) deserializing a DB row whose properties/columns blob was written by an incompatible Druid version, hand-edited, truncated, or otherwise not parseable into TableSpec/TableProperties.","commonSituations":"Upgraded Druid reading catalog rows written by an older/newer schema; manual UPDATE of DB blobs; DB corruption or byte truncation; inserting rows via external tooling with wrong serialization.","solutions":["Inspect the offending row's blob in the DB and repair or delete the malformed row.","Restore the metadata DB from backup if corruption is widespread.","Confirm the Druid version reading the table matches the version that wrote it; migrate data if schemas changed.","If a single table is bad, drop and re-create it through the catalog API."],"exampleFix":"// diagnosis: find the bad row, then fix via API\n// before: corrupted row causes ISE on every read\n// after\ndbi.update(\"DELETE FROM druid_catalog_tables WHERE table_name = ?\", badTable);\nmanager.createTable(id, rebuiltSpec);","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  TableMetadata t = manager.readTable(id);\n} catch (ISE e) {\n  if (e.getMessage().contains(\"Failed to deserialize a DB object\")) {\n    // flag row as corrupt; repair DB or restore from backup\n  }\n}","preventionTips":["Never edit catalog DB blobs manually.","Keep writer and reader Druid versions aligned; plan migration for schema changes.","Back up the metadata database before upgrades.","Monitor for DB corruption/truncation issues."],"tags":["json","deserialization","data-corruption"],"backgroundTag":"json-unmarshal-failed","analyzedSha":"9b90983fd291f26935af934383ce360473179e4d","analyzedAt":"2026-09-07T13:32:30.957Z","contentChangedAt":"2026-09-07T13:32:30.957Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}