tonhowtf/omniget · error

invalid JSON

Error message

invalid JSON: {e}

What it means

parse_json first deserializes the raw cookie-export content with serde_json::from_str; if the content is not syntactically valid JSON it wraps serde's error as 'invalid JSON: {e}'. This is the outermost gate before the array/object shape check and per-cookie parsing.

Solutions

  1. Validate the file is real JSON (e.g. JSON.parse in JS or jq . in shell) before importing.
  2. Export cookies in JSON format from the extension — do not pass cookies.txt / Netscape-format files to parse_json.
  3. Strip a UTF-8 BOM and any leading/trailing whitespace before parsing.
  4. Fix syntax errors named in the message (serde reports line/column) — trailing commas, unquoted keys, comments.
  5. If you need Netscape support, convert cookies.txt to JSON first or add a format-detecting wrapper.

Example fix

// before
let cookies = parsers::parse_json(&std::fs::read_to_string("cookies.txt")?)?; // Netscape text

// after
let content = std::fs::read_to_string("cookies.json")?;
let content = content.trim_start_matches('\u{feff}');
serde_json::from_str::<serde_json::Value>(content) // pre-validate
    .map_err(|e| anyhow::anyhow!("cookie export is not valid JSON: {e}"))?;
let cookies = parsers::parse_json(content)?;
Defensive patterns

Strategy: validation

Validate before calling

function validateCookieExport(text) {
  const cleaned = text.replace(/^\uFEFF/, '').trim();
  if (!cleaned.startsWith('[') && !cleaned.startsWith('{')) {
    throw new Error('cookie export must be JSON (array or object), not cookies.txt');
  }
  JSON.parse(cleaned); // throws with position on syntax errors
  return cleaned;
}

Type guard

function isCookieJson(text) {
  try { const v = JSON.parse(text); return Array.isArray(v) || (v && typeof v === 'object'); }
  catch { return false; }
}

Try / catch

try {
  const cookies = await invoke('parse_cookies', { content: fileText });
} catch (e) {
  if (String(e).startsWith('invalid JSON:')) {
    showError('The selected file is not valid JSON. Export cookies as JSON, not cookies.txt.');
  } else throw e;
}

Prevention

When it happens

Trigger: Calling parse_json (directly or via parse/parse_for_domain and the parse_json_* wrappers) with content that fails serde_json parsing: empty string, raw Netscape cookie-file text, JSON with trailing commas or comments, HTML error pages pasted instead of the export, BOM-prefixed or truncated files.

Common situations: User imports a cookies.txt (Netscape format) file instead of a JSON export; file truncated mid-transfer; editing the export by hand and breaking syntax; clipboard content with surrounding text or smart quotes; empty export from a fresh extension profile.

Understand the failure class

Background: JSON parse error: "Unexpected token" / "not valid JSON" / "failed to parse" — what JSON parsers are really complaining about — this error's family across 45 libraries.

Related errors


AI-assisted analysis of tonhowtf/omniget@8600b91f42 (2026-09-12). Data as JSON: /api/errors/08d69fe9dce1d08a. Report an issue: GitHub.

Appendix: source

Thrown at src-tauri/src/cookies/parsers.rs:202

    #[serde(default, alias = "httpOnly")]
    http_only: Option<bool>,
    #[serde(default)]
    secure: Option<bool>,
    #[serde(default, alias = "expirationDate", alias = "expires")]
    expiration: Option<f64>,
    name: String,
    value: String,
    #[serde(default, alias = "hostOnly")]
    host_only: Option<bool>,
    #[serde(default, alias = "sameSite")]
    same_site: Option<String>,
    #[serde(default)]
    session: Option<bool>,
}

pub fn parse_json(content: &str) -> anyhow::Result<Vec<ExtensionCookie>> {
    let raw: serde_json::Value =
        serde_json::from_str(content).map_err(|e| anyhow::anyhow!("invalid JSON: {e}"))?;
    let arr = match raw {
        serde_json::Value::Array(a) => a,
        serde_json::Value::Object(_) => vec![raw],
        _ => anyhow::bail!("Expected a JSON array of cookie objects."),
    };
    let mut cookies = Vec::with_capacity(arr.len());
    for item in arr {
        let parsed: JsonCookie = match serde_json::from_value(item) {
            Ok(c) => c,
            Err(_) => continue,
        };
        let expires = match (parsed.session.unwrap_or(false), parsed.expiration) {
            (true, _) => 0,
            (false, Some(f)) => f as i64,
            (false, None) => 0,
        };
        cookies.push(ExtensionCookie {
            domain: parsed.domain,

View on GitHub (pinned to 8600b91f42)