SearchTranslationUnitsMasked(): Object reference not set to an instance of an object

I have developed a plugin which is a connector to a simple Machine Translation REST API, similar to the Microsoft Bing API. The authorisation works fine, but when I select Translate Single Document from the Welcome page, select a file, select my plugin from the Translation Memory and Automated Translation screen, the error Object reference not set to an instance of an object comes up.

Looking at the stack trace in the SDL error log below, it appears that the error isn’t produced directly within my code, but maybe this error is due to a null reference being returned somewhere.

I have put extensive logging in my plugin, and there is an edited and prettyfied version of it below.

The main points are as follows:

  • SearchTranslationUnitsMasked() seems to be called once whenever a target segment is activated. It is passed only one segment, when clearly this function is intended to be called for multiple segments. Is this an SDL bug?

  • The first time it is called the mask parameter contains [true]. The second and all subsequent calls to it, mask is [false, true] which implies that there are two segments, when in fact there is only one, and that the first segment should not be translated. Ignoring the mask parameter allows second and subsequent segments to be translated, but otherwise makes no difference to the behaviour.

  • The call to the MT API is successful, and the values returned from SearchTranslationUnitsMasked appear to be correct.

  • The functions called after SearchTranslationUnitsMasked() look correct, and don’t return null.

Can anybody help me?

Extracts from the logs follow, making this a very long post, so if posting code would help please ask, and I’ll be happy to oblige.

The SDL error log

<SDLErrorDetails time="12/14/2016 10:35:34 AM">
  <ErrorMessage>Object reference not set to an instance of an object.</ErrorMessage>
  <Exception>
    <Type>System.NullReferenceException, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</Type>
    <HelpLink />
    <Source>Sdl.TranslationStudio.Common</Source>
    <HResult>-2147467261</HResult>
    <StackTrace><![CDATA[

at Sdl.TranslationStudio.Common.TranslationMemory.AbstractTranslationMemoryControl`1
    .CreateTranslationUnitParagraphs(
        IList`1 tus, IDocumentProperties documentProperties, IBilingualDocumentWriter writer
    )

at Sdl.TranslationStudio.Common.TranslationMemory.AbstractTranslationMemoryControl`1
    .CreateParagraphs(IList`1 tus)

at Sdl.TranslationStudio.Common.TranslationMemory.AbstractTranslationMemoryControl`1
    .ShowTranslationUnits(IList`1 tus)

at Sdl.TranslationStudio.Common.TranslationMemory.SearchResultTranslationMemoryControl
    .ShowTranslationUnits(IList`1 tus)

at Sdl.TranslationStudio.Common.TranslationMemory.AbstractTranslationMemoryControl`1
    .set_TranslationUnits(IList`1 value)

at Sdl.TranslationStudio.Editor.TranslationMemory
    .CompoundTranslationMemorySearchResultsControl.SetSearchResults(
        SearchResults searchResults
    )

at Sdl.TranslationStudio.Editor.TranslationMemory.
    CompoundTranslationMemorySearchResultsControl.SetSearchResults(
        SearchResults searchResults, IEnumerable`1 cascadeMessages
    )

at Sdl.TranslationStudio.Editor.TranslationMemory.TranslationMemoryViewPartControl
    .UpdateContent()

at Sdl.TranslationStudio.Editor.TranslationMemory.TranslationMemoryViewPartControl
    .TranslationJob_StatusChanged(IJob job)

at Sdl.Desktop.Platform.Services.JobEventHandler.Invoke(IJob job)

at Sdl.Desktop.Platform.Implementation.Services.Job.OnStatusChanged()

at Sdl.Desktop.Platform.Implementation.Services.Job.SetStatus(JobStatus status)

at Sdl.Desktop.Platform.Implementation.Services.Job._worker_RunWorkerCompleted(
    Object sender, RunWorkerCompletedEventArgs e
)

at System.ComponentModel.BackgroundWorker.OnRunWorkerCompleted(
    RunWorkerCompletedEventArgs e
)

at System.ComponentModel.BackgroundWorker.AsyncOperationCompleted(Object arg)

]]>
    </StackTrace>
  </Exception>
  <Environment>
    <ProductName>SDL Trados Studio</ProductName>
    <ProductVersion>12.0.0.0</ProductVersion>
    <EntryAssemblyFileVersion>12.2.5195.7</EntryAssemblyFileVersion>
    <OperatingSystem>Microsoft Windows Server 2012 R2 Standard</OperatingSystem>
    <ServicePack>NULL</ServicePack>
    <OperatingSystemLanguage>1033</OperatingSystemLanguage>
    <CodePage>1252</CodePage>
    <LoggedOnUser>WIN-1TK4REQGE9E\Administrator</LoggedOnUser>
    <DotNetFrameWork>4.0.30319.42000</DotNetFrameWork>
    <ComputerName>WIN-1TK4REQGE9E</ComputerName>
    <ConnectedToNetwork>True</ConnectedToNetwork>
    <PhysicalMemory>4193904 MB</PhysicalMemory>
  </Environment>
</SDLErrorDetails>

Plugin logs

Smatr is the class which implements ITranslationProvider

SmatrLanguageDirection is the class which implements ITranslationProviderLanguageDirection

Before SearchTranslationUnitsMasked() is called

SmatrLanguageDirection::TranslationProvider.get():TranslationProvider:smatr.Smatr
Smatr::Name().get():Capita-TI SmartMATE for Trados
SmatrLanguageDirection::TranslationProvider.get():provider:smatr.Smatr
Smatr::TranslationMethod.get():start
Smatr::TranslationMethod.get():MachineTranslation:end
SmatrLanguageDirection::TranslationProvider.get():TranslationProvider:smatr.Smatr
SmatrLanguageDirection::TranslationProvider.get():TranslationProvider:smatr.Smatr

Inputs to SearchTranslationUnitsMasked()

settings

SmatrLanguageDirection::SearchTranslationUnitsMasked():begin
SmatrLanguageDirection::SearchTranslationUnitsMasked():settings:{
	"Mode":1,
	"MachineTranslationLookup":0,
	"IsDocumentSearch":false,
	"Penalties":[
		{"PenaltyType":2,"Malus":1},
		{"PenaltyType":1,"Malus":1},
		{"PenaltyType":6,"Malus":1},
		{"PenaltyType":9,"Malus":1}
	],
	"CheckMatchingSublanguages":false,
	"Filters":[],
	"AutoLocalizationSettings":{
		"LongDatePattern":"dddd d MMMM yyyy",
		"ShortDatePattern":"dd/MM/yyyy",
		"LongTimePattern":"HH:mm:ss",
		"UnitSeparationMode":0,
		"UnitSeparator":"\u0000",
		"ShortTimePattern":"HH:mm",
		"LocalizationParametersSource":0,
		"DisableAutoSubstitution":127
	},
	"HardFilter":null,
	"SortSpecification":{
		"Criteria":[
			{"FieldName":"sco","Direction":1},
			{"FieldName":"chd","Direction":1},
			{"FieldName":"usc","Direction":1}
		]
	},
	"ComputeTranslationProposal":true,
	"CurrentStructureContext":null,
	"MinScore":70,
	"MaxResults":5,
	"AdaptiveMachineTranslationLookupMode":0
} 

translationUnits[]

SmatrLanguageDirection::SearchTranslationUnitsMasked():translationUnits:[
	{
		"SourceSegment":{
			"Elements":[
				{"Value":"Polar bears are ..."}
			],
			"Tokens":null,
			"CultureName":"en-US"
		},
		"TargetSegment":null,
		"Contexts":{"Values":[]},
		"AlignmentData":null,
		"AlignModelDate":null,
		"InsertDate":null,
		"Origin":0,
		"ConfirmationLevel":0,
		"Format":0,
		"SystemFields":{
			"CreationDate":"0001-01-01T00:00:00",
			"ChangeDate":"0001-01-01T00:00:00",
			"UseDate":"0001-01-01T00:00:00",
			"UseUser":null,
			"UseCount":0,
			"CreationUser":null,
			"ChangeUser":null
		},
		"FieldValues":[],
		"ResourceId":{
			"Id":0,
			"Guid":"00000000-0000-0000-0000-000000000000"
		}
	}
]

mask[]

SmatrLanguageDirection::SearchTranslationUnitsMasked():mask:[true]

Output returned from SearchTranslationUnitsMasked()

Return value

SmatrLanguageDirection::SearchTranslationUnitsMasked():returning:[
	[
		{
			"ScoringResult":{
				"BaseScore":0,
				"ResolvedPlaceables":0,
				"EditDistance":null,
				"MatchingConcordanceRanges":null,
				"MemoryTagsDeleted":false,
				"TagMismatch":false,
				"AppliedPenalties":null,
				"TargetSegmentDiffers":false,
				"TextContextMatch":0,
				"IsStructureContextMatch":false
			},
			"MemoryPlaceables":null,
			"PlaceableAssociations":null,
			"MemoryTranslationUnit":{
				"SourceSegment":{
					"Elements":[
						{"Value":"Polar bears are ... "}
					],
					"Tokens":null,
					"CultureName":"en-US"
				},
				"TargetSegment":{
					"Elements":[
						{"Value":"Les ours polaires sont ... "}
					],
					"Tokens":null,
					"CultureName":"fr-FR"
				},
				"Contexts":{
					"Values":[]
				},
				"AlignmentData":null,
				"AlignModelDate":null,
				"InsertDate":null,
				"Origin":2,
				"ConfirmationLevel":1,
				"Format":0,
				"SystemFields":{
					"CreationDate":"0001-01-01T00:00:00",
					"ChangeDate":"0001-01-01T00:00:00",
					"UseDate":"0001-01-01T00:00:00",
					"UseUser":null,
					"UseCount":0,
					"CreationUser":null,
					"ChangeUser":null
				},
				"FieldValues":[],
				"ResourceId":{
					"Id":39543988,
					"Guid":"00000000-0000-0000-0000-000000000000"
				}
			},
			"TranslationProposal":null,
			"ContextData":null,
			"CascadeEntryIndex":-1
		}
	]
]
SmatrLanguageDirection::SearchTranslationUnitsMasked():end

After SearchTranslationUnitsMasked()

SmatrLanguageDirection::TranslationProvider.get():TranslationProvider:smatr.Smatr
Smatr::TranslationMethod.get():start
Smatr::TranslationMethod.get():MachineTranslation:end

After the error message is dismissed, every time a new target cell is selected the error returns, and the log sections above are repeated, however the mask is passed as [false, true] on the second and all subsequent attempts.
Also, the translation is performed successfully for the source segment selected if the first element of mask is forced to be true.