{"record":{"id":"ac829cd76f6c33f3","repo":"apache/hadoop","slug":"counter-table-not-initialized-table","errorCode":null,"errorMessage":"Counter table not initialized: {table}","messagePattern":"Counter table not initialized: (.+?)","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"hadoop-hdfs-project/hadoop-hdfs-rbf/src/main/java/org/apache/hadoop/hdfs/server/federation/router/security/token/DistributedSQLCounter.java","lineNumber":72,"sourceCode":"   * @return counter value.\n   * @throws SQLException if querying the database fails.\n   */\n  public int selectCounterValue() throws SQLException {\n    try (Connection connection = connectionFactory.getConnection()) {\n      return selectCounterValue(false, connection);\n    }\n  }\n\n  private int selectCounterValue(boolean forUpdate, Connection connection) throws SQLException {\n    String query = String.format(\"SELECT %s FROM %s %s\", field, table,\n        forUpdate ? \"FOR UPDATE\" : \"\");\n    LOG.debug(\"Select counter statement: \" + query);\n    try (Statement statement = connection.createStatement();\n        ResultSet result = statement.executeQuery(query)) {\n      if (result.next()) {\n        return result.getInt(field);\n      } else {\n        throw new IllegalStateException(\"Counter table not initialized: \" + table);\n      }\n    }\n  }\n\n  /**\n   * Sets the counter to the given value.\n   *\n   * @param value Value to assign to counter.\n   * @throws SQLException if querying the database fails.\n   */\n  public void updateCounterValue(int value) throws SQLException {\n    try (Connection connection = connectionFactory.getConnection(true)) {\n      updateCounterValue(value, connection);\n    }\n  }\n\n  /**\n   * Sets the counter to the given value.","sourceCodeStart":54,"sourceCodeEnd":90,"githubUrl":"https://github.com/apache/hadoop/blob/2add9630210752f88ceb1bb74eb65e37bf41da8e/hadoop-hdfs-project/hadoop-hdfs-rbf/src/main/java/org/apache/hadoop/hdfs/server/federation/router/security/token/DistributedSQLCounter.java#L54-L90","documentation":"DistributedSQLCounter expects a pre-provisioned single-row table ('One record must exist on the table at all times') — LastSequenceNum(sequenceNum) and LastDelegationKeyId(keyId) for the SQL-backed Router token secret manager. selectCounterValue runs 'SELECT <field> FROM <table> [FOR UPDATE]'; if the ResultSet has no rows it throws IllegalStateException('Counter table not initialized: <table>'). It fires while reserving token sequence numbers or delegation key ids, typically at Router startup or first token operation, and callers like SQLDelegationTokenSecretManager wrap it into RuntimeException.","triggerScenarios":"The counter tables exist but were never seeded with their initial row (DDL ran, seed INSERT skipped); someone truncated or deleted the counter rows; the JDBC URL points at a fresh/wrong schema so the SELECT hits an empty table; table-name case mismatch (e.g. Linux MySQL lower_case_table_names) resolving to a different empty table.","commonSituations":"First rollout of the MySQL-backed Router delegation token store where the schema script was applied without its seed statements; DBA cleanup that emptied 'small' tables; environment migration to a new database that recreated structure but not data.","solutions":["Seed the counter rows: INSERT INTO LastSequenceNum(sequenceNum) VALUES (0); INSERT INTO LastDelegationKeyId(keyId) VALUES (0); — if tokens/keys already exist, seed with SELECT MAX(sequenceNum) FROM Tokens / MAX(keyId) FROM DelegationKeys to avoid duplicate ids.","Confirm the tables the JDBC connection actually targets: run SHOW TABLES and SELECT * against the same URL/user the Router uses.","Restart the Router (or retry the token operation) after seeding — the counters are read at startup and on batch exhaustion.","Guard the provisioning script so DDL and seed INSERT always ship together."],"exampleFix":"-- before: table created but empty\nCREATE TABLE LastSequenceNum (sequenceNum INT NOT NULL);\n\n-- after: create and seed the mandatory single row\nCREATE TABLE LastSequenceNum (sequenceNum INT NOT NULL);\nINSERT INTO LastSequenceNum (sequenceNum) VALUES (0);","handlingStrategy":"validation","validationCode":"// Pre-flight: counter tables must contain exactly one seeded row\ntry (Connection c = dataSource.getConnection();\n     Statement s = c.createStatement();\n     ResultSet rs = s.executeQuery(\"SELECT COUNT(*) FROM LastSequenceNum\")) {\n  rs.next();\n  if (rs.getInt(1) != 1) {\n    throw new IllegalStateException(\"LastSequenceNum not seeded: run the seed INSERT\");\n  }\n}","typeGuard":null,"tryCatchPattern":"try {\n  int seq = secretManager.getDelegationTokenSeqNum();\n} catch (RuntimeException e) {\n  if (e.getCause() instanceof IllegalStateException\n      && e.getCause().getMessage().contains(\"Counter table not initialized\")) {\n    // seed LastSequenceNum/LastDelegationKeyId and retry, don't fabricate ids\n    throw new provisioning error pointing at the seed script;\n  }\n  throw e;\n}","preventionTips":["Ship schema DDL and seed INSERTs as one idempotent migration script (CREATE TABLE IF NOT EXISTS + INSERT if COUNT(*)=0).","Forbid TRUNCATE/DELETE on LastSequenceNum/LastDelegationKeyId in DBA runbooks.","After any restore/migration, run the COUNT(*)=1 pre-flight before starting routers."],"tags":["hdfs","router-based-federation","delegation-token","mysql","sql","data-initialization"],"backgroundTag":"sql-seed-data-missing","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-23T01:17:44.959Z"}