influxdata/influxdb · error · CatalogError

token hash already exists

Error message

token hash already exists

What it means

This error is thrown when the hash of a token being created already exists in the catalog. Token hashes must be unique because they are the lookup key for authenticating requests; a duplicate hash indicates the same token secret was generated (or reused) twice.

Solutions

  1. Generate a fresh token secret instead of reusing an existing one
  2. Check the catalog for the duplicate token entry and remove the stale one
  3. If restoring from backup, deduplicate tokens before import
  4. Retry the operation — cryptographic hash collisions from fresh random secrets are effectively impossible

Example fix

// before
let token = "influxdb3_token_fixed"; // reused secret
create_token_with_secret(token)?;
// after
let token = generate_random_token(); // fresh secret each run
create_token_with_secret(&token)?;
Defensive patterns

Strategy: retry

Try / catch

match create_token_with_secret(secret) {
    Err(CatalogError::TokenHashAlreadyExists) => retry_with_fresh_secret(),
    r => r,
}

Prevention

When it happens

Trigger: Creating a token whose generated hash collides with an existing token hash — practically, retrying token creation with the same pre-shared token string, or catalog data containing duplicated token hashes.

Common situations: Importing/restoring catalogs where token rows were duplicated; deterministic token generation in scripts producing the same secret; replaying a token-creation request against a restored catalog.

Understand the failure class

Background: "already exists" / EEXIST / FileAlreadyExistsException: what the 'file already exists' error means and how to fix it — this error's family across 37 libraries.

Related errors


AI-assisted analysis of influxdata/influxdb@06200ef96b (2026-09-19). Data as JSON: /api/errors/d5b20e78916131db. Report an issue: GitHub.

Appendix: source

Thrown at influxdb3_catalog/src/error.rs:285

    #[error("last cache size must be greater than 0")]
    InvalidLastCacheSize,

    #[error("failed to parse trigger from {trigger_spec}{}", .context.as_ref().map(|context| format!(": {context}")).unwrap_or_default())]
    TriggerSpecificationParseError {
        trigger_spec: String,
        context: Option<String>,
    },

    #[error("invalid error behavior {0}")]
    InvalidErrorBehavior(String),

    #[error("cannot parse token permission, {0}")]
    CannotParsePermissionForToken(String),

    #[error("token name already exists, {0}")]
    TokenNameAlreadyExists(String),

    #[error("token hash already exists")]
    TokenHashAlreadyExists,

    #[error("missing admin token, cannot update")]
    MissingAdminTokenToUpdate,

    #[error("cannot delete internal db")]
    CannotDeleteInternalDatabase,

    #[error("cannot modify internal db")]
    CannotModifyInternalDatabase,

    #[error("tried to stop a node ({node_id}) that is already stopped")]
    NodeAlreadyStopped { node_id: Arc<str> },

    #[error(
        "node '{node_id}' is not fully stopped (current state: {current_state}); run \"stop node\" first"
    )]
    NodeNotFullyStopped {

View on GitHub (pinned to 06200ef96b)