jdx/mise · error

Postgres database must contain only letters, numbers, and…

Error message

Postgres database must contain only letters, numbers, and underscores

What it means

The postgres database option is used both as a URI component and as a SQL identifier, so expand validates it up front: it must be non-empty and contain only ASCII letters, digits, and underscores. Anything else is rejected before any files or processes are touched.

Solutions

  1. Rename the database to use only letters, numbers, and underscores (e.g. my_db)
  2. Remove characters like '-', '.', or spaces from the database value
  3. Ensure the database key is non-empty

Example fix

# before
database = "my-db"
# after
database = "my_db"
Defensive patterns

Strategy: validation

Validate before calling

const validDb = (db) => /^[A-Za-z0-9_]+$/.test(db);

Type guard

const isSafeDbName = (v) => typeof v === 'string' && v.length > 0 && /^[A-Za-z0-9_]+$/.test(v);

Prevention

When it happens

Trigger: A daemon preset config sets a database name containing hyphens, dots, spaces, or other non-alphanumeric characters, or an empty database string, and expand validates it.

Common situations: Naming a database 'my-db' or 'my.db' (hyphens/dots rejected); quoting or whitespace accidentally included in the TOML string; leaving database = "" in the config.

Understand the failure class

Background: "invalid id" errors: invalid identifier format — why libraries reject IDs before lookup, and how to fix them — this error's family across 37 libraries.

Related errors


AI-assisted analysis of jdx/mise@533346cc37 (2026-09-17). Data as JSON: /api/errors/befb0cbf273269cd. Report an issue: GitHub.

Appendix: source

Thrown at src/daemons/presets.rs:92

        }
    }
    let database = preset
        .options
        .get("database")
        .map(|value| {
            value
                .as_str()
                .ok_or_else(|| eyre::eyre!("options.database must be a string"))
        })
        .transpose()?
        .unwrap_or("postgres");
    // This name is also used as a URI component and SQL identifier.
    if database.is_empty()
        || !database
            .chars()
            .all(|c| c.is_ascii_alphanumeric() || c == '_')
    {
        bail!("Postgres database must contain only letters, numbers, and underscores");
    }
    let data = state_dir(root).join("data").join(name);
    let mut context = tera::Context::new();
    context.insert("data", &quote(data.to_string_lossy()));
    context.insert("port", &port);
    context.insert("database", database);
    let mut renderer = crate::tera::get_tera(Some(root));
    let mut table = preset.daemon;
    for (_, value) in table.iter_mut() {
        if let toml::Value::String(text) = value {
            *text = crate::tera::render_str(&mut renderer, text, &context)?;
        }
    }
    if let Some(toml::Value::String(command)) = table.get_mut("ready_cmd") {
        *command = format!(
            "{} x -- sh -c {}",
            quote(crate::env::MISE_BIN.to_string_lossy()),
            quote(command.as_str())

View on GitHub (pinned to 533346cc37)