{"record":{"id":"84389eb8fc2370ea","repo":"microsoft/typescript-go","slug":"w-exactly-one-of-configdirectory-or-configfilena","errorCode":null,"errorMessage":"%w: exactly one of configDirectory or configFileName is required","messagePattern":"%w: exactly one of configDirectory or configFileName is required","errorType":"validation","errorClass":"ErrClientError","httpStatus":null,"severity":"error","filePath":"internal/api/session.go","lineNumber":1178,"sourceCode":"\t\t}, nil\n\t}\n\n\tconfig, parseErrors := tsoptions.ParseConfigFileTextToJson(\n\t\tconfigFileName,\n\t\ts.toPath(configFileName),\n\t\tconfigFileContent,\n\t)\n\tresponse := &ReadConfigFileResponse{Config: config}\n\tif len(parseErrors) > 0 {\n\t\tresponse.Error = NewDiagnosticResponse(parseErrors[0])\n\t}\n\treturn response, nil\n}\n\n// handleParseJsonConfigFileContent parses an in-memory JSON configuration.\nfunc (s *Session) handleParseJsonConfigFileContent(ctx context.Context, params *ParseJsonConfigFileContentParams) (*ConfigFileResponse, error) {\n\tif (params.ConfigDirectory == nil) == (params.ConfigFileName == nil) {\n\t\treturn nil, fmt.Errorf(\"%w: exactly one of configDirectory or configFileName is required\", ErrClientError)\n\t}\n\n\tvar basePath string\n\tvar configFileName string\n\tif params.ConfigDirectory != nil {\n\t\tbasePath = tspath.GetNormalizedAbsolutePath(*params.ConfigDirectory, s.projectSession.GetCurrentDirectory())\n\t} else {\n\t\tconfigFileName = params.ConfigFileName.ToAbsoluteFileName(s.projectSession.GetCurrentDirectory())\n\t\tbasePath = tspath.GetDirectoryPath(configFileName)\n\t}\n\n\tparsedCommandLine := tsoptions.ParseJsonConfigFileContent(\n\t\tjsonValueToAny(params.JSON),\n\t\ts.projectSession,\n\t\tbasePath,\n\t\tnil, /*existingOptions*/\n\t\tconfigFileName,\n\t\tnil, /*resolutionStack*/","sourceCodeStart":1160,"sourceCodeEnd":1196,"githubUrl":"https://github.com/microsoft/typescript-go/blob/1bcfa18d79a3be41772223d5c05dfe4480e614ff/internal/api/session.go#L1160-L1196","documentation":"parseJsonConfigFileContent requires exactly one of configDirectory (string) and configFileName (DocumentIdentifier) to locate the in-memory JSON config; the handler enforces XOR and rejects both-set and neither-set. The chosen value determines the base path used to resolve relative file names inside the config.","triggerScenarios":"Sending both fields; sending neither (e.g. both null or the whole object omitted); client serialization that always emits both keys with defaults.","commonSituations":"Porting from the classic tsserver API where only a directory was needed; JSON built from a struct with both fields populated; omitempty left off so empty strings/objects still count as present on the wire only when non-nil pointers are set.","solutions":["Decide which anchor you need: configDirectory to resolve a config body against a folder, or configFileName when the JSON came from a named file","Send exactly one of the two fields and omit the other entirely"],"exampleFix":"// before\nparams := {json: cfg, configDirectory: \"/proj\", configFileName: {uri: \"file:///proj/tsconfig.json\"}}\n\n// after\nparams := {json: cfg, configDirectory: \"/proj\"}","handlingStrategy":"validation","validationCode":"func buildConfigParams(jsonBody packagejson.JSONValue, dir string) (api.ParseJsonConfigFileContentParams, error) {\n    p := api.ParseJsonConfigFileContentParams{JSON: jsonBody}\n    if dir != \"\" {\n        p.ConfigDirectory = &dir\n        return p, nil\n    }\n    return p, fmt.Errorf(\"configDirectory or configFileName required\")\n}\n// XOR check mirrors the server: (ConfigDirectory == nil) != (ConfigFileName == nil)","typeGuard":"func validConfigAnchor(p *api.ParseJsonConfigFileContentParams) bool {\n    if p == nil { return false }\n    return (p.ConfigDirectory == nil) != (p.ConfigFileName == nil)\n}","tryCatchPattern":null,"preventionTips":["Decide up front whether you anchor the config at a directory or a named file, and send only that field","Add a unit test asserting exactly one of the two pointers is set before each call"],"tags":["config","validation","tsconfig","api"],"backgroundTag":null,"analyzedSha":"1bcfa18d79a3be41772223d5c05dfe4480e614ff","analyzedAt":"2026-08-16T02:12:00.115Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}