microsoft/TypeScript · error · Error
${option.name} is a string value; tsconfig JSON must be pars
Error message
${option.name} is a string value; tsconfig JSON must be parsed with parseJsonSourceFileConfigFileContent or getParsedCommandLineOfConfigFile before passing to createProgram What it means
Thrown by `ts.createProgram` when a compiler option of custom type (e.g. `target`, `module`, `moduleResolution`, `jsx`, `newLine`, `target`-family enums) is still a raw string. These options must be parsed into their numeric enum form first; a leftover string means the tsconfig JSON was not run through `parseJsonSourceFileConfigFileContent` / `getParsedCommandLineOfConfigFile` / `parseJsonConfigFileContent` before being passed in.
Source
Thrown at src/compiler/program.ts:1526
* @param options - The compiler options which should be used.
* @param host - The host interacts with the underlying file system.
* @param oldProgram - Reuses an old program structure.
* @param configFileParsingDiagnostics - error during config file parsing
* @returns A 'Program' object.
*/
export function createProgram(rootNames: readonly string[], options: CompilerOptions, host?: CompilerHost, oldProgram?: Program, configFileParsingDiagnostics?: readonly Diagnostic[]): Program;
export function createProgram(_rootNamesOrOptions: readonly string[] | CreateProgramOptions, _options?: CompilerOptions, _host?: CompilerHost, _oldProgram?: Program, _configFileParsingDiagnostics?: readonly Diagnostic[]): Program {
let _createProgramOptions = isArray(_rootNamesOrOptions) ? createCreateProgramOptions(_rootNamesOrOptions, _options!, _host, _oldProgram, _configFileParsingDiagnostics) : _rootNamesOrOptions; // TODO: GH#18217
const { rootNames, options, configFileParsingDiagnostics, projectReferences, typeScriptVersion, host: createProgramOptionsHost } = _createProgramOptions;
let { oldProgram } = _createProgramOptions;
// Stop referencing these objects to ensure GC collects them.
_createProgramOptions = undefined!;
_rootNamesOrOptions = undefined!;
for (const option of commandLineOptionOfCustomType) {
if (hasProperty(options, option.name)) {
if (typeof options[option.name] === "string") {
throw new Error(`${option.name} is a string value; tsconfig JSON must be parsed with parseJsonSourceFileConfigFileContent or getParsedCommandLineOfConfigFile before passing to createProgram`);
}
}
}
const reportInvalidIgnoreDeprecations = memoize(() => createOptionValueDiagnostic("ignoreDeprecations", Diagnostics.Invalid_value_for_ignoreDeprecations));
let processingDefaultLibFiles: SourceFile[] | undefined;
let processingOtherFiles: SourceFile[] | undefined;
let files: SourceFile[];
let symlinks: SymlinkCache | undefined;
let typeChecker: TypeChecker;
let classifiableNames: Set<__String>;
let filesWithReferencesProcessed: Set<Path> | undefined;
let cachedBindAndCheckDiagnosticsForFile: Map<Path, readonly Diagnostic[]> | undefined;
let cachedDeclarationDiagnosticsForFile: Map<Path, readonly DiagnosticWithLocation[]> | undefined;
const programDiagnostics = createProgramDiagnostics(getCompilerOptionsObjectLiteralSyntax);
let automaticTypeDirectiveNames: string[] | undefined;
View on GitHub (pinned to b465fdbfe1)
Solutions
- Parse the config with `ts.parseJsonConfigFileContent` (or `parseJsonSourceFileConfigFileContent`/`getParsedCommandLineOfConfigFile`) and pass `parsed.options` to `createProgram`.
- If building options by hand, use the enum: `{ target: ts.ScriptTarget.ES2020 }` instead of a string.
- Map known string values through `ts.optionDeclarations`/the relevant parser instead of forwarding them raw.
Example fix
// before
const opts = JSON.parse(fs.readFileSync("tsconfig.json", "utf8")).compilerOptions;
const prog = ts.createProgram(["a.ts"], opts); // target/module are strings -> throws
// after
const parsed = ts.parseJsonConfigFileContent(
ts.readConfigFile("tsconfig.json", ts.sys.readFile).config,
ts.sys,
".",
);
const prog = ts.createProgram(parsed.fileNames, parsed.options); Defensive patterns
Strategy: validation
Validate before calling
// Ensure no custom-type option is a string before calling createProgram:
for (const opt of ts.commandLineOptionOfCustomType) {
if (opts[opt.name] != null && typeof opts[opt.name] === "string") {
throw new Error(`${opt.name} must be parsed (run parseJsonConfigFileContent)`);
}
} Type guard
function isParsedOptions(opts: ts.CompilerOptions): boolean {
return ts.commandLineOptionOfCustomType.every(o => typeof opts[o.name] !== "string");
} Prevention
- Always obtain `CompilerOptions` through `parseJsonConfigFileContent` or `getParsedCommandLineOfConfigFile`, not `JSON.parse`.
- When building options by hand, use the `ts.ScriptTarget`/`ts.ModuleKind`/etc. enums.
- Add a unit test that feeds a real tsconfig through your toolchain.
When it happens
Trigger: Passing hand-built `CompilerOptions` where a custom-type field is a string literal (e.g. `{ target: "es2020" }`), or forwarding raw JSON-derived options straight into `createProgram` without a parsed-config step.
Common situations: Custom tooling/build scripts that read tsconfig via `JSON.parse` and pass `options` directly; IDE plugins that construct a program from scratch; migrating from an older TS version that was lenient about this.
Related errors
- Could not resolve JS module '${moduleName}' starting at '${i
- tracing requires having fs\n(original error: ${e.message ||
- start < 0
- length < 0
- newLength < 0
AI-assisted analysis of microsoft/TypeScript@b465fdbfe1 (2026-08-12).
Data as JSON: /api/errors/02780fb224cf737f.
Report an issue: GitHub.