Forum Discussion
404 error downloading file versions via CSOM (SharePoint 2013 On-Prem)
I need to download historical versions of a document from a SharePoint 2013 On Premises document library using a C# console application, so I can migrate them chronologically to SharePoint Online along with their column properties. While downloading the current latest version works perfectly, downloading older historical versions always fails.
- Standard CSOM methods fail because ListItem.Versions does not exist in the SharePoint 2013 v15 SDK.
- Reverting to direct HTTP endpoints consistently throws an error.
Here is the exact exception message I receive:
System.Net.Http.HttpRequestException: Response status code does not indicate success: 404 (Not Found).
Below is the minimal reproducible code example demonstrating how the connection is initialized, how properties are loaded, and where the download fails on historical versions:
using System;
using System.IO;
using System.Net.Http;
using Microsoft.SharePoint.Client;
using SP = Microsoft.SharePoint.Client;
class Program
{
static void Main()
{
string siteUrl = "https://example.com";
using (ClientContext sourceCtx = new ClientContext(siteUrl))
{
sourceCtx.Credentials = System.Net.CredentialCache.DefaultCredentials;
List sourceList = sourceCtx.Web.Lists.GetByTitle("MyLibrary");
CamlQuery query = CamlQuery.CreateAllItemsQuery();
ListItemCollection items = sourceList.GetItems(query);
sourceCtx.Load(items, ic => ic.Include(
item => item.Id,
item => item.File,
item => item.File.Versions,
item => item.File.ServerRelativeUrl
));
sourceCtx.ExecuteQuery();
foreach (ListItem item in items)
{
if (item.File == null || !item.File.Exists) continue;
foreach (FileVersion ver in item.File.Versions)
{
string absoluteVersionUrl = siteUrl.TrimEnd('/') + "/" + ver.Url.TrimStart('/');
using (var handler = new HttpClientHandler { Credentials = sourceCtx.Credentials })
using (var client = new HttpClient(handler))
{
client.DefaultRequestHeaders.Add("X-FORMS_BASED_AUTH_ACCEPTED", "f");
client.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0");
// CRITICAL FAILURE HERE: Always throws 404 Not Found
HttpResponseMessage response = client.GetAsync(absoluteVersionUrl).Result;
response.EnsureSuccessStatusCode();
using (Stream fileStream = response.Content.ReadAsStreamAsync().Result)
{
// Upload logic to SPO goes here
}
}
}
}
}
}The version URL returned inside the property matches the following virtual folder layout format: _vti_history/512/Folder/Doc.docx
My specific environment queries are:
- Why does navigating to the absolute history folder URL over an authenticated HttpClient trigger a 404 Not Found error in SharePoint 2013 on premises, even though the path token is extracted directly from the version url metadata property?
- Is there an alternative legacy REST endpoint routing structure or an alternative file stream extraction method available in the SharePoint 2013 (v15) SDK that allows an external client application to fetch older version binaries successfully?