microsoft/typescript-go · error · Error

Expected version in .custom-gcl.yml

Error message

Expected version in .custom-gcl.yml

What it means

After the trace file is closed and the legend successfully marshaled, StopTracing writes legend.json into traceDir via fs.WriteFile. This error means that final write failed — the trace events and types dumps may exist, but the legend that maps them is missing, so downstream tooling cannot correlate checkers with their type files. It is the legend-side counterpart of the header-write error at startup.

Source

Thrown at Herebyfile.mjs:852

    dependencies: [tsgo, buildAPITests],
    run: async () => {
        // Prevent interleaving by running these directly instead of in parallel.
        await runTests();
        await runTestBenchmarks();
        await runTestTools();
        await runTestAPI();
    },
});

const customLinterPath = "./_tools/custom-gcl";
const customLinterHashPath = customLinterPath + ".hash";

const golangciLintPackage = memoize(() => {
    const golangciLintYml = fs.readFileSync(".custom-gcl.yml", "utf8");
    const pattern = /^version:\s*(v\d+\.\d+\.\d+).*$/m;
    const match = pattern.exec(golangciLintYml);
    if (!match) {
        throw new Error("Expected version in .custom-gcl.yml");
    }
    const version = match[1];
    const major = version.split(".")[0];
    const versionSuffix = ["v0", "v1"].includes(major) ? "" : "/" + major;

    return `github.com/golangci/golangci-lint${versionSuffix}/cmd/golangci-lint@${version}`;
});

const customlintHash = memoize(() => {
    const files = glob.sync([
        "./_tools/go.mod",
        "./_tools/customlint/**/*",
        "./.custom-gcl.yml",
    ], {
        ignore: "**/testdata/**",
        nodir: true,
        absolute: true,
    });

View on GitHub (pinned to 1bcfa18d79)

Solutions

  1. Re-run with a writable, existing traceDir (os.MkdirAll it first and confirm ownership/permissions).
  2. Free disk space — legend.json is tiny but the write still fails on a full volume.
  3. Keep the trace directory untouched for the whole process lifetime; schedule cleanup only after the process exits.
  4. If legend.json is a directory or root-owned file from an earlier run, remove it before tracing.

Example fix

// before
tr, _ := tracing.StartTracing(fs, traceDir, cfg, false)
defer tr.StopTracing()

// after: guarantee writable teardown
if err := os.MkdirAll(traceDir, 0o755); err != nil { return err }
tr, err := tracing.StartTracing(fs, traceDir, cfg, false)
if err != nil { return err }
defer func() { _ = tr.StopTracing() }()
Defensive patterns

Strategy: validation

Validate before calling

// ensure legend.json is writable at teardown as well
info, err := os.Stat(traceDir)
if err != nil || !info.IsDir() || info.Mode().Perm()&0o200 == 0 {
	return fmt.Errorf("trace dir missing or read-only: %s", traceDir)
}

Try / catch

if err := tr.StopTracing(); err != nil {
	if strings.Contains(err.Error(), "failed to write legend file") {
		// trace.json and types_*.json may exist; legend mapping is lost — re-run to get a complete set
		log.Printf("legend missing, trace incomplete set: %v", err)
	}
}

Prevention

When it happens

Trigger: StopTracing when traceDir or legend.json is not writable: directory deleted mid-session, read-only mount at teardown, permission change, disk full at the final write, or legend.json existing as a directory.

Common situations: Trace output directory removed or locked by cleanup jobs while the process was still running; disk exhaustion right at exit; containers unmounting volumes before graceful shutdown completes; running as a different user than the one that created traceDir.

Related errors


AI-assisted analysis of microsoft/typescript-go@1bcfa18d79 (2026-08-16). Data as JSON: /api/errors/f73f8b448ea11452. Report an issue: GitHub.