microsoft/typescript-go · error · ErrClientError

%w: could not read file %q

Error message

%w: could not read file %q

What it means

parseConfigFile could not read the tsconfig file from the server filesystem: FS().ReadFile returned !ok after normalizing params.File against the session's current directory. It means the file does not exist at the resolved absolute path, is unreadable, or the DocumentIdentifier's uri/fileName form resolves differently than the caller assumed.

Source

Thrown at internal/api/session.go:1208

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

// handleParseConfigFile parses a tsconfig.json file and returns its contents.
func (s *Session) handleParseConfigFile(ctx context.Context, params *ParseConfigFileParams) (*ConfigFileResponse, error) {
	configFileName := params.File.ToAbsoluteFileName(s.projectSession.GetCurrentDirectory())
	configFileContent, ok := s.projectSession.FS().ReadFile(configFileName)
	if !ok {
		return nil, fmt.Errorf("%w: could not read file %q", ErrClientError, configFileName)
	}

	configDir := tspath.GetDirectoryPath(configFileName)
	tsConfigSourceFile := tsoptions.NewTsconfigSourceFileFromFilePath(
		configFileName,
		s.toPath(configFileName),
		configFileContent,
	)
	parsedCommandLine := tsoptions.ParseJsonSourceFileConfigFileContent(
		tsConfigSourceFile,
		s.projectSession,
		configDir,
		nil, /*existingOptions*/
		nil, /*existingOptionsRaw*/
		configFileName,
		nil, /*resolutionStack*/
		nil, /*extraFileExtensions*/
		nil, /*extendedConfigCache*/

View on GitHub (pinned to 1bcfa18d79)

Solutions

  1. Pass an absolute, normalized path in the file field
  2. Verify the file exists from the server process's view before calling
  3. Confirm the cwd the session was created with (it drives relative-path normalization) and send absolute paths to avoid depending on it

Example fix

// before
parseConfigFile({file: "tsconfig.json"}) // relative; depends on server cwd

// after
parseConfigFile({file: "/abs/path/to/project/tsconfig.json"})
Defensive patterns

Strategy: validation

Validate before calling

func readableConfig(absPath string) bool {
    if !filepath.IsAbs(absPath) { return false }
    info, err := os.Stat(absPath)
    return err == nil && !info.IsDir()
}
// Note: the server stats this from ITS filesystem; verify from the same host/user when possible.

Type guard

func isAbsoluteFile(p string) bool { return filepath.IsAbs(p) }

Try / catch

if err != nil && strings.Contains(err.Error(), "could not read file") {
    return fmt.Errorf("tsconfig not readable by server: %q (check path, case, permissions)", cfgPath)
}

Prevention

When it happens

Trigger: Passing a relative file name that normalizes against a different server cwd than expected; a URI whose FileName() form differs by case or separators from the on-disk path; the config file deleted or not checked out; permission denied on the file.

Common situations: Client and server in different working directories or containers; Windows path casing/separator mismatches; sparse checkouts missing the config; symlinks pointing outside the visible FS.

Related errors


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