Offline Map Sync Error: Job error 6004 \"invalid start of json - expecting { or [\". < : 0."

1144
6
11-19-2020 11:02 AM
JoeHershman
MVP Regular Contributor

I get this error on a regular basis when syncing an offline map.  I have noticed it seems to occur when I sync soon after opening a map, and before I have loaded the map into a MapView.  I do check to confirm the map and all layers have a LoadStatus = Loaded.

{
	"isServerMessage": false,
	"message": "Layer result: Sync failed. Name: LayerName LayerID: 9 TableName: ... URL: https://services3.arcgis.com/..../arcgis/rest/services/..../FeatureServer/9 Job error 6004 \"invalid start of json - expecting { or [\". < : 0.",
	"severity": "warning",
	"timestamp": 1605810526949
}

The was this post a couple years ago: https://community.esri.com/t5/arcgis-runtime-sdk-for-android/quot-invalid-start-of-json-expecting-or...

But no resolution ever presented

0 Kudos
6 Replies
JoeHershman
MVP Regular Contributor

Anything?  This is to where it seems to happen the first time we sync the map no matter what

@MichaelBranscomb 

@dotMorten_esri 

0 Kudos
MichaelBranscomb
Esri Frequent Contributor

Hi Joe,

Without a repro it's difficult to tell, but it appears to be returning something other than the expected JSON response, perhaps HTML. Could it be authentication-related? (although a challenge should trigger the registered Authentication Manager challenge)

You could (for debugging purposes only), add an event handler for the response end event and log the responses.

e.g.

Register handler:

 

ArcGISHttpClientHandler.HttpResponseEnd += OnHttpResponseEnd;

 

 

Event handler:

 

private async void OnHttpResponseEnd(object sender, HttpResponseEndEventArgs e)
{
    using (e.GetDeferral())
    {
        // Await the original response
        var oldContent = e.Response.Content;
        var bytes = await oldContent.ReadAsByteArrayAsync().ConfigureAwait(false);
                
        // Get the response string
        string responseString = Encoding.ASCII.GetString(bytes);
        // TODO : Log the response
        // e.g. Use a TextWriterTraceListener and call Trace.TraceInformation(responseString);

        // Wrap it in a new ByteArrayContent so it can be consumed again
        var newContent = new ByteArrayContent(bytes);
        foreach (var header in oldContent.Headers)
            newContent.Headers.TryAddWithoutValidation(header.Key, header.Value);
        e.Response.Content = newContent;
    }
}

 

 

Thanks

Mike

0 Kudos
JoeHershman
MVP Regular Contributor

Mike,

I put the handler in place - required I upgrade the Runtime as it was not there in 100.6.  

The log includes a "OnHttpResponseEnd" line before any log entry from there to differentiate from other locations.  I also log other pertinent aspects of the process. 

Primary aspects of the log that relate to the timing of the HttpResponse messages

 

_log.Debug("STARTING SYNC");
var results = await job.GetResultAsync();
_log.Debug("SYNC COMPLETE");

 

I also log to show when the ChallengeHandler is requested

 

public async Task<Credential> CreateCredentialAsync(CredentialRequestInfo info)
{
	try
	{
		_log.Info($"CHALLENGE  ********** : {info.ServiceUri} ***********");
		if ( info.ServiceUri == null ) return null;

		var credential = await AuthenticationManager.Current.GenerateCredentialAsync(info.ServiceUri, Settings.UserName, Settings.Password);

		_log.Info($"RETURN credential *********: {info.ServiceUri} ********");
		return credential;
	}
	catch (Exception e)
	{
		_log.Error(e, e.Message);

		return null;
	}
}

 

It seems the call is made to GetResultAsync which then does not have any token, so it calls into the ChallngeHandler to get a token.  What seems to be happening, though is the Sync request is still processing while the Challenge is also occurring.  So, the sync is trying to process without actually waiting for the token to be returned.  Then you get some bizarre returning of all the html copies of the sync request pages (which I assume is where our json errors come from).

Then I go into a sync again and it all works, I assume because the previous request for a token is complete.  I had previously tried some other things to using a ChallengeHandler which had similar results but I don't have logging for right now.

Prior to making the sync call instead of using a ChallengeHandler I simply added the credential

 

AuthenticationManager.Current.AddCredential(await _portalManager.Credential(true));

 

Also I had things setup that the user connects to AGOL when they first log into the application, this way I can test that the user entered credentials are valid when the user first opens the application instead of waiting until they are doing something requiring a connection (sync or downloading an offline map).

If my assumption is correct how can I process the Credential requests and be sure they are 100% complete prior to attempting the sync?

I will email you he log file because the new GeoNet does not seem to want to allow me to upload

0 Kudos
JoeHershman
MVP Regular Contributor

So I tried this with the change that I first log onto AGOL prior to the sync, in that case I see similar results except it never actually goes into the ChallengeHandler.  I was thinking maybe it has to do with the WebMap, but I tried with another WebMap and seems to still have the issue.  I am having a hard time with no one being able to duplicate with this happening every single time I try a first sync.  I am willing to share the code, privately, if someone is willing to do that. 

0 Kudos
JoeHershman
MVP Regular Contributor

I added this to occur in my processing which seems to resolve the issue, not really excited about it as a workaround, but for now will have to do

private bool _firstSync = true;

private async Task InitialzeTokens()
{
	if ( !_firstSync ) return;

	foreach (var featureLayer in _map.OperationalLayers.OfType<FeatureLayer>())
	{
		var pars = new QueryParameters {WhereClause = "1=0", MaxFeatures = 1};

		if ( !(featureLayer.FeatureTable is GeodatabaseFeatureTable gdbFeatureTable) ) continue;
		if ( gdbFeatureTable.Geodatabase?.Source == null ) continue;

		var serviceFeatureTable = new ServiceFeatureTable(gdbFeatureTable.Geodatabase.Source);

		try
		{
			await serviceFeatureTable.LoadAsync();
			var _ = await serviceFeatureTable.QueryFeaturesAsync(pars);
		}
		catch (Exception)
		{
			//_log.Error(e, e.Message);
		}
	}

	_firstSync = false;
}
0 Kudos
imritanshu
New Contributor III

I am getting same error in fieldmaps android version 22.0.1 Build 1050.  

Can anybody suggest is there any limitation of number of layers or the area? 

@MichaelBranscomb 

0 Kudos