If you depend on the TFVC Client Object Model or tf.exe in your Azure Pipelines, then you may be getting  TF14067 errors. This is likely being caused by the agent depending on a different version of the TFS Client Object Model than the one you are using.

I recently ran into this issue when Microsoft upgraded tf.exe that ships with the Azure Pipelines agent, and my TFVC Pipeline Tasks started failing everywhere. Repopulating the workspace cache is the simple fix for this issue. And it looks like I'm not alone, as similar questions on StackOverflow suggest.

When you bump into this issue, you'll see the following cryptic error message that mentions:

  1. TF14067
  2. A path you are absolutely certain exists
  3. A workspace name that was created minutes before when the build agent initialized
TF14067: The item {path} could not be found in the ws_{id};Project Collection Build Service workspace, or you do not have permission to access it.

Solution

Option 1: Migrate to Git

Seriously. TFVC has been on life-support for a long time, has not been receiving new feature love in a long time and doesn't match the often fast-paced and distributed nature of today's organisations.

Azure DevOps, and even Team Foundation Server before it, has had a simple Import feature to convert a stable TFVC branch into a fresh Git Repository. It may then take some work to clean up the repo to adhere to the latest clean repo standards, but technically the change is pretty straightforward.

Use Import repository to convert from TFVC to Git.
Pick the branch and pull it in.

Option 2: Use my TFVC Pipelines Tasks

To help a client migrate from XAML to, back then, Visual Studio Online, I built the TFVC Pipeline tasks. A small set of simple tasks that allow you to run a couple of common TFVC scenarios as part of your build pipeline.

- task: tf-vc-checkin@2
  displayName: 'Check changes into source control'
  inputs:
    ConfirmUnderstand: true
    BypassGatedCheckin: true
    OverridePolicy: true
    OverridePolicyReason: 'Override!'
    Recursion: Full

I've recently released version 2, which adds improved and cleaned-up YAML support and uses the latest agent features so it can last a little while longer.

These tasks are an easy way to buy a little more time while training your teams and prepare the migration to Git.

Option 3: Install and use the correct tf.exe.

Each version of the agent ships with a copy of the TFS Client Object Model. TFVC relies on a local workspace cache which must be populated for each version of the TFS Client Object Model. The agent only populates the cache for its own use.

By using a version of tf.exe that was built with the same major version number of the TFS Client Object Model, it can piggy-back on the cache that was populated by the agent.

Option 4: Force workspace cache population

You can force the population of the workspace cache on a different major version from the command-line:

> tf vc workspaces /collection:$(System.TeamFoundationCollectionUri) /computer:$(Agent.MachineName)

Or from code:

$versionControlServer = $tfsTeamProjectCollection.GetService([Microsoft.TeamFoundation.VersionControl.Client.VersionControlServer])
$workstation = [Microsoft.TeamFoundation.VersionControl.Client.Workstation]::Current
$workstation.EnsureUpdateWorkspaceInfoCache($versionControlServer, $versionControlServer.AuthorizedUser)

Final thoughts

When I wrote the TFVC tasks back in 2015, it was to help a client make the transition from their TFS 2012 XAML build to the, back then, new build system. This allowed them to go all-in on, back then, Visual Studio Online and migrate to Git. We're now almost in 2020. which raises the question...

Why are people still heavily dependent on TFVC and only now migrating away from XAML builds? The new build agent introduced in 2015 build agent has already had 2 major versions, XAML has officially been deprecated, Visual Studio Online has been renamed to Visual Studio Team Services and then to Azure DevOps. We've reached the point that many folks are already migrating from UI based build definitions to YAML.

It's time to move on!