Hmbown/CodeWhale · error · anyhow::Error
external agy credential file {} is not a SQLite database
Error message
external agy credential file {} is not a SQLite database What it means
The granted file was secure-opened (regular file, no symlink leaf) but its first 16 bytes do not start with the 15-byte SQLite magic `SQLite format 3`. This is a cheap format check before any SQLite parsing, so a wrong-path grant or an empty/corrupted credential store fails fast and safely.
Source
Thrown at crates/tui/src/agy_credentials.rs:98
if grant.source() != ExternalCredentialSource::AgyCli {
bail!(
"Antigravity import requires an agy_cli grant, not {}",
grant.source().as_str()
);
}
let path = grant.path();
// Secure-open the exact granted path first: regular file only, no
// symlink/reparse-point leaf, size-capped before any SQLite parsing.
let mut file = crate::external_credentials::open_external_regular_file(path)?;
let mut header = [0u8; 16];
let read = file.read(&mut header).with_context(|| {
format!(
"reading SQLite header of {}",
codewhale_config::quote_os_path(path)
)
})?;
if read < 16 || header[..15] != *b"SQLite format 3" {
bail!(
"external agy credential file {} is not a SQLite database",
codewhale_config::quote_os_path(path)
);
}
file.seek(SeekFrom::Start(0)).ok();
let metadata = file
.metadata()
.with_context(|| format!("statting {}", codewhale_config::quote_os_path(path)))?;
if metadata.len() > AGY_STATE_DB_LIMIT {
bail!(
"external agy credential store {} exceeds the {} byte safety limit",
codewhale_config::quote_os_path(path),
AGY_STATE_DB_LIMIT
);
}
// Pin the file identity: SQLite reopens the path by name, so hold the
// secure handle open across the query and prove the inode did not move.
let pinned = file_identity(&file);View on GitHub (pinned to 0c42157ee5)
Solutions
- Point the read-only grant at the real agy SQLite credential store (commonly `<profile>/state.vscdb`) and retry.
- Verify the file before import: `head -c 15 <path>` should print `SQLite format 3` (or `file <path>` reports SQLite 3.x).
- If the store is missing/truncated, launch the Antigravity/IDE client so it recreates state.vscdb, then re-authenticate.
Example fix
// before let grant = consent_for(path_join(&profile, "state.json")); // wrong file let token = antigravity_oauth_token_from_grant(&grant)?; // after let grant = consent_for(path_join(&profile, "state.vscdb")); // real SQLite store let token = antigravity_oauth_token_from_grant(&grant)?;
Defensive patterns
Strategy: validation
Validate before calling
let mut f = std::fs::File::open(grant.path())?;
let mut magic = [0u8; 16];
use std::io::Read as _;
let n = f.read(&mut magic)?;
if n < 16 || magic[..15] != *b"SQLite format 3" {
anyhow::bail!("granted path is not a SQLite db; check the consent entry");
} Type guard
fn looks_like_sqlite(header: &[u8]) -> bool {
header.len() >= 16 && &header[..15] == b"SQLite format 3"
} Try / catch
match antigravity_oauth_token_from_grant(&grant) {
Ok(t) => t,
Err(e) if e.to_string().contains("is not a SQLite database") => { /* fix grant path; re-consent */ return Err(e) }
Err(e) => return Err(e),
} Prevention
- Name the exact state.vscdb file in the consent entry instead of a directory or glob.
- Smoke-test the granted path with `file` or a 16-byte header read before running a full import.
- Ensure the agy client has actually created and signed into its state store before import.
When it happens
Trigger: antigravity_oauth_token_from_grant where the granted path is 0–15 bytes long, or its header differs from `SQLite format 3` — e.g. the grant points at a JSON/log/config file, a truncated state.vscdb, or a placeholder created by tooling.
Common situations: Consent config names the wrong file under the agy/IDE profile directory; the IDE stores credentials in a different file after a version change; the state.vscdb was copied incompletely or is mid-recreation after a crash.
Related errors
- external agy credential store {} exceeds the {} byte safety
- Antigravity import requires an agy_cli grant, not {}
- external agy credential store {} changed while being read
- agy OAuth token member `{member}` is empty
- agy OAuth token JSON carries no access token member
AI-assisted analysis of Hmbown/CodeWhale@0c42157ee5 (2026-08-20).
Data as JSON: /api/errors/521beccd8a9b36a8.
Report an issue: GitHub.