{"record":{"id":"87417ecace5626e9","repo":"t8y2/dbx","slug":"tdengine-database-is-required","errorCode":null,"errorMessage":"TDengine database is required","messagePattern":"TDengine database is required","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"agents/drivers/tdengine/src/driver.rs","lineNumber":823,"sourceCode":"                .await\n                .map_err(|_| anyhow!(\"TDengine operation timed out after {timeout_secs} seconds\"))?\n                .map_err(anyhow::Error::from)\n        }\n    };\n    tokio::select! {\n        _ = token.cancelled() => bail!(\"TDengine operation was cancelled\"),\n        result = operation => result,\n    }\n}\n\nfn effective_database<'a>(requested: &'a str, current: &'a str) -> Result<&'a str> {\n    let requested = requested.trim();\n    if !requested.is_empty() {\n        return validate_database_name(requested);\n    }\n    let current = current.trim();\n    if current.is_empty() {\n        bail!(\"TDengine database is required\");\n    }\n    validate_database_name(current)\n}\n\nfn validate_database_name(value: &str) -> Result<&str> {\n    let value = value.trim();\n    let mut chars = value.chars();\n    let valid_start = chars.next().is_some_and(|char| char == '_' || char.is_ascii_alphabetic());\n    if !valid_start || !chars.all(|char| char == '_' || char.is_ascii_alphanumeric()) {\n        bail!(\"invalid TDengine database name: {value}\");\n    }\n    Ok(value)\n}\n\nfn table_from_show_row(row: Vec<Value>, table_type: &str, includes_stable_name: bool) -> Option<TableInfo> {\n    let name = row.first().and_then(json_text)?.to_string();\n    let parent_name = includes_stable_name\n        .then(|| row.get(3).and_then(json_text).map(str::trim).filter(|value| !value.is_empty()).map(str::to_string))","sourceCodeStart":805,"sourceCodeEnd":841,"githubUrl":"https://github.com/t8y2/dbx/blob/c0390bff16418b651f4728520d99adf8ce48829a/agents/drivers/tdengine/src/driver.rs#L805-L841","documentation":"effective_database resolves which TDengine database an operation targets: it prefers the explicitly requested name, otherwise falls back to the connection's current database. If both are empty, there is no database context and the driver errors, because list_tables/list_objects/get_columns/get_object_source/get_create_sql all need a database scope.","triggerScenarios":"Calling list_tables, list_objects, get_columns, get_object_source, or get_create_sql with an empty requested database on a connection that never had use_database called (or was created without a default database).","commonSituations":"Connecting to a TDengine server without specifying a default database, then browsing tables/metadata; or passing an empty string instead of a database name.","solutions":["Call use_database on the connection first, or pass the database name explicitly to the metadata API","Specify a default database in the connection params when connecting","Verify the requested name passes validate_database_name (no stray whitespace/invalid characters)"],"exampleFix":"// before\ndriver.list_tables(&conn, \"\", ...).await?; // no current db\n// after\ndriver.use_database(&conn, \"metrics\", ...).await?;\ndriver.list_tables(&conn, \"metrics\", ...).await?;","handlingStrategy":"validation","validationCode":"anyhow::ensure!(!db.trim().is_empty() || !current_db.trim().is_empty(), \"TDengine database is required\");","typeGuard":"fn resolves_database(requested: &str, current: &str) -> bool {\n    !requested.trim().is_empty() || !current.trim().is_empty()\n}","tryCatchPattern":null,"preventionTips":["Always set a default database at connect time","Call use_database before metadata APIs","Never pass empty strings for database names"],"tags":["rust","tdengine","database","metadata","validation"],"backgroundTag":"missing-required-parameter","analyzedSha":"c0390bff16418b651f4728520d99adf8ce48829a","analyzedAt":"2026-09-05T23:05:10.900Z","contentChangedAt":"2026-09-05T23:05:10.900Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}