JanDeDobbeleer/oh-my-posh · warning

cannot extract TFM from %s project file

Error message

cannot extract TFM from %s project file

What it means

When scanning a .NET (dotnet) project file for the project segment, the parser looks for the TargetFrameworkMoniker (TFM) value. If no TFM is found in the project file, it logs 'cannot extract TFM from <file> project file' — notably this is only logged; the function still returns ProjectData with an empty Target.

Source

Thrown at src/segments/project.go:400

				target = values["TFM"]
			}
		}
	}

	// mirror MSBuild's implicit import of Directory.Build.props when the
	// project/solution itself does not define a TargetFramework
	if target == "" {
		if props, err := n.env.HasParentFilePath("Directory.Build.props", false); err == nil {
			propsContent := n.env.FileContent(props.Path)
			values = regex.FindNamedRegexMatch(tag, propsContent)
			if len(values) != 0 {
				target = values["TFM"]
			}
		}
	}

	if target == "" {
		log.Error(fmt.Errorf("cannot extract TFM from %s project file", name))
	}

	return &ProjectData{
		Target: target,
		Name:   name,
	}
}

// Scans rootEntries and their subdirectories breadth-first, up to maxDepth levels deep.
// Paths are kept relative to pwd so FileContent resolves them the same way the caller does.
func (n *Project) findProjectFile(rootEntries []fs.DirEntry, maxDepth int) string {
	projectExts := []string{".csproj", ".fsproj", ".vbproj"}
	pwd := n.env.Pwd()

	var dirs []string
	for _, entry := range rootEntries {
		if entry.IsDir() {
			dirs = append(dirs, entry.Name())

View on GitHub (pinned to 0976794618)

Solutions

  1. Add an explicit `<TargetFramework>` element to the project file
  2. For multi-targeted projects, pick a single framework or accept the empty Target and rely on the project name display
  3. Check the project file is a standard MSBuild format the parser supports
  4. This is logged-only: verify whether the empty Target actually breaks your template; if not, it can be ignored

Example fix

<!-- before -->
<Project><PropertyGroup><TargetFrameworks>net8.0;net6.0</TargetFrameworks></PropertyGroup></Project>
<!-- after: parser-readable single TFM -->
<Project><PropertyGroup><TargetFramework>net8.0</TargetFramework></PropertyGroup></Project>
Defensive patterns

Strategy: validation

Validate before calling

// grep the project file for a TFM before enabling
content, _ := os.ReadFile("myapp.csproj")
hasTFM := strings.Contains(string(content), "<TargetFramework>")

Prevention

When it happens

Trigger: Parsing an SDK-style csproj/fsproj/vbproj that declares no resolvable TFM (no TargetFramework/TargetFrameworkMoniker property), a multi-targeted project using TargetFrameworks, or a legacy/non-standard project layout whose property names differ.

Common situations: Multi-targeting (`<TargetFrameworks>net8.0;net6.0</TargetFrameworks>`) which the simple parser doesn't pick up; project files generated by non-MSBuild tools; solution containing test/utility projects without an explicit TFM.

Related errors


AI-assisted analysis of JanDeDobbeleer/oh-my-posh@0976794618 (2026-08-31). Data as JSON: /api/errors/01cebc4337948b46. Report an issue: GitHub.