denoland/deno · error

existing {} is not valid JSON/JSONC: {e}. Fix or remove it a

Error message

existing {} is not valid JSON/JSONC: {e}. Fix or remove it and re-run `deno sync-types`.

What it means

The ensure-root step of tsconfig generation refuses to touch an existing root tsconfig.json it cannot parse: `jsonc_parser::parse_to_ast` fails on the file's contents (comments and trailing commas allowed, so failures are real syntax errors). Because silently overwriting user content would destroy data, an unparseable file is a hard `InvalidData` error and the message instructs you to fix or remove it and re-run `deno sync-types`.

Source

Thrown at cli/tsc/tsconfig_gen.rs:322

      .expect("failed to serialize tsconfig");
    return std::fs::write(&root_tsconfig_path, &content);
  }

  // Parse as JSONC and edit the raw text by byte range (rather than
  // re-serializing) so the user's comments and formatting are preserved. An
  // unparseable file is a hard error rather than being silently overwritten.
  use jsonc_parser::ast::ObjectPropName;
  use jsonc_parser::ast::Value as JsoncValue;
  let ast = jsonc_parser::parse_to_ast(
    &content,
    &jsonc_parser::CollectOptions {
      comments: jsonc_parser::CommentCollectionStrategy::Off,
      tokens: false,
    },
    &jsonc_parser::ParseOptions::default(),
  )
  .map_err(|e| {
    std::io::Error::new(
      std::io::ErrorKind::InvalidData,
      format!(
        "existing {} is not valid JSON/JSONC: {e}. Fix or remove it and re-run \
         `deno sync-types`.",
        root_tsconfig_path.display()
      ),
    )
  })?;

  let Some(JsoncValue::Object(obj)) = ast.value else {
    // Not a JSON object (empty file, array, ...) — leave it alone.
    return Ok(());
  };
  let extends = obj.properties.iter().find(|p| {
    let name = match &p.name {
      ObjectPropName::String(s) => s.value.as_ref(),
      ObjectPropName::Word(w) => w.value,
    };

View on GitHub (pinned to 9ad36f7a2c)

Solutions

  1. Inspect tsconfig.json for conflict markers (`<<<<<<<`/`=======`/`>>>>>>>`) or truncation and repair the syntax, then re-run `deno sync-types`.
  2. If the file is not precious, back it up or remove it and re-run — the command regenerates a valid one.
  3. Run `git diff --check` / a JSONC lint before syncing to catch damaged files early.

Example fix

# before
$ deno sync-types
# → existing /repo/tsconfig.json is not valid JSON/JSONC: ...

# after (repair, or regenerate)
$ git checkout -- tsconfig.json && deno sync-types
$ rm tsconfig.json && deno sync-types
Defensive patterns

Strategy: validation

Validate before calling

# ensure the root tsconfig parses before deno sync-types
deno eval 'import { parse } from "jsr:@std/jsonc"; parse(Deno.readTextSync("tsconfig.json"));'

Try / catch

try {
  await runDeno("sync-types");
} catch (err) {
  if (String(err).includes("not valid JSON/JSONC")) {
    // fix the file, or rename it away and re-run to regenerate
  } else throw err;
}

Prevention

When it happens

Trigger: Running `deno sync-types` when a root tsconfig.json already exists but contains unparseable content — typically unresolved git merge-conflict markers, encoding corruption, or a truncated write.

Common situations: Repos mid-rebase with conflict markers left in tsconfig.json; files damaged by a crash or partial save; committed files with non-UTF-8 bytes from a bad merge.

Related errors


AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20). Data as JSON: /api/errors/c9a027fc20cb7889. Report an issue: GitHub.