microsoft/typescript-go · error · ErrClientError

%w: exactly one of configDirectory or configFileName is requ

Error message

%w: exactly one of configDirectory or configFileName is required

What it means

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.

Source

Thrown at internal/api/session.go:1178

		}, nil
	}

	config, parseErrors := tsoptions.ParseConfigFileTextToJson(
		configFileName,
		s.toPath(configFileName),
		configFileContent,
	)
	response := &ReadConfigFileResponse{Config: config}
	if len(parseErrors) > 0 {
		response.Error = NewDiagnosticResponse(parseErrors[0])
	}
	return response, nil
}

// handleParseJsonConfigFileContent parses an in-memory JSON configuration.
func (s *Session) handleParseJsonConfigFileContent(ctx context.Context, params *ParseJsonConfigFileContentParams) (*ConfigFileResponse, error) {
	if (params.ConfigDirectory == nil) == (params.ConfigFileName == nil) {
		return nil, fmt.Errorf("%w: exactly one of configDirectory or configFileName is required", ErrClientError)
	}

	var basePath string
	var configFileName string
	if params.ConfigDirectory != nil {
		basePath = tspath.GetNormalizedAbsolutePath(*params.ConfigDirectory, s.projectSession.GetCurrentDirectory())
	} else {
		configFileName = params.ConfigFileName.ToAbsoluteFileName(s.projectSession.GetCurrentDirectory())
		basePath = tspath.GetDirectoryPath(configFileName)
	}

	parsedCommandLine := tsoptions.ParseJsonConfigFileContent(
		jsonValueToAny(params.JSON),
		s.projectSession,
		basePath,
		nil, /*existingOptions*/
		configFileName,
		nil, /*resolutionStack*/

View on GitHub (pinned to 1bcfa18d79)

Solutions

  1. Decide which anchor you need: configDirectory to resolve a config body against a folder, or configFileName when the JSON came from a named file
  2. Send exactly one of the two fields and omit the other entirely

Example fix

// before
params := {json: cfg, configDirectory: "/proj", configFileName: {uri: "file:///proj/tsconfig.json"}}

// after
params := {json: cfg, configDirectory: "/proj"}
Defensive patterns

Strategy: validation

Validate before calling

func buildConfigParams(jsonBody packagejson.JSONValue, dir string) (api.ParseJsonConfigFileContentParams, error) {
    p := api.ParseJsonConfigFileContentParams{JSON: jsonBody}
    if dir != "" {
        p.ConfigDirectory = &dir
        return p, nil
    }
    return p, fmt.Errorf("configDirectory or configFileName required")
}
// XOR check mirrors the server: (ConfigDirectory == nil) != (ConfigFileName == nil)

Type guard

func validConfigAnchor(p *api.ParseJsonConfigFileContentParams) bool {
    if p == nil { return false }
    return (p.ConfigDirectory == nil) != (p.ConfigFileName == nil)
}

Prevention

When it happens

Trigger: Sending both fields; sending neither (e.g. both null or the whole object omitted); client serialization that always emits both keys with defaults.

Common situations: 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.

Related errors


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