microsoft/TypeScript · error · Error

You need to change the source code of fourslash test to use

Error message

You need to change the source code of fourslash test to use replaceWithSemanticClassifications

What it means

Thrown unconditionally by replaceWithSemanticClassifications to force the test author to stop using the auto-replacement helper. The method computes the semantic-classification assertions and builds a replacement string, but the file-rewrite logic below the throw is commented out — the throw is the intended behaviour. It exists so legacy fourslash tests calling verify.replaceWithSemanticClassifications("2020") are flagged for manual migration to explicit classification assertions.

Source

Thrown at src/harness/fourslashImpl.ts:3216

                expected.join(","),
                actual.fileNames!.map(file => {
                    return file.replace(this.basePath + "/", "");
                }).join(","),
            );
        }
    }

    public replaceWithSemanticClassifications(format: ts.SemanticClassificationFormat.TwentyTwenty): void {
        const actual = this.languageService.getSemanticClassifications(this.activeFile.fileName, ts.createTextSpan(0, this.activeFile.content.length), format);
        const replacement = [`const c2 = classification("2020");`, `verify.semanticClassificationsAre("2020",`];
        for (const a of actual) {
            const identifier = this.classificationToIdentifier(a.classificationType as number);
            const text = this.activeFile.content.slice(a.textSpan.start, a.textSpan.start + a.textSpan.length);
            replacement.push(`    c2.semanticToken("${identifier}", "${text}"), `);
        }
        replacement.push(");");

        throw new Error("You need to change the source code of fourslash test to use replaceWithSemanticClassifications");

        // const fs = require("fs");
        // const testfilePath = this.originalInputFileName.slice(1);
        // const testfile = fs.readFileSync(testfilePath, "utf8");
        // const newfile = testfile.replace("verify.replaceWithSemanticClassifications(\"2020\")", replacement.join("\n"));
        // fs.writeFileSync(testfilePath, newfile);
    }

    public verifyEncodedSyntacticClassificationsLength(expected: number): void {
        const actual = this.languageService.getEncodedSyntacticClassifications(this.activeFile.fileName, ts.createTextSpan(0, this.activeFile.content.length));
        if (actual.spans.length !== expected) {
            this.raiseError(`encodedSyntacticClassificationsLength failed - expected total spans to be ${expected} got ${actual.spans.length}`);
        }
    }

    public verifyEncodedSemanticClassificationsLength(format: ts.SemanticClassificationFormat, expected: number): void {
        const actual = this.languageService.getEncodedSemanticClassifications(this.activeFile.fileName, ts.createTextSpan(0, this.activeFile.content.length), format);
        if (actual.spans.length !== expected) {

View on GitHub (pinned to b465fdbfe1)

Solutions

  1. Run the test and capture the replacement strings printed/emitted before the throw — they contain the c2.semanticToken(...) lines and the verify.semanticClassificationsAre call.
  2. Paste those generated lines into the test source, replacing the verify.replaceWithSemanticClassifications("2020") call.
  3. Remove the replaceWithSemanticClassifications call entirely so the test now uses verify.semanticClassificationsAre with explicit token assertions.
  4. If the test is not yours, check for an upstream migration in a newer TypeScript revision.

Example fix

// before
verify.replaceWithSemanticClassifications("2020");
// after — generated lines pasted into the test
verify.semanticClassificationsAre("2020",
    c2.semanticToken("keyword", "const"),
    c2.semanticToken("identifier", "x"),
);
Defensive patterns

Strategy: validation

Validate before calling

// Never call this in committed tests — it is a one-shot migration helper.
// If you must run it, do so in a throwaway branch and capture stdout before the throw.

Try / catch

try {
    verify.replaceWithSemanticClassifications("2020");
} catch (e) {
    // This always throws; capture the generated replacement lines from the
    // partially-built `replacement` array via a debug breakpoint, then migrate manually.
}

Prevention

When it happens

Trigger: A fourslash test contains verify.replaceWithSemanticClassifications("2020") (mapped to state.replaceWithSemanticClassifications). The method always throws regardless of file content because the migration scaffolding beneath it is disabled.

Common situations: Encountered when running an old fourslash test that was never migrated from the old classification verification style. The test was designed to be run once to generate assertions, then the generated output pasted into the test body.

Related errors


AI-assisted analysis of microsoft/TypeScript@b465fdbfe1 (2026-08-12). Data as JSON: /api/errors/d32c2063361e3cee. Report an issue: GitHub.