Unexpected exception when configuring file multiFileConverter for task 'Pre-translate Files': Failed to create an instance of translation provider 'sdltm.https://<groupshare-url.com>'.

Hi everyone,

I’m facing an issue with a tool I’ve developed that automates project creation using Trados templates.

I’ll outline how the tool works and the problem I’m encountering, hoping someone can guide me.

Tool Workflow:

  1. The tool retrieves a Trados template and associated files.
  2. It checks for Translation Providers and adds credentials, regardless of whether they were previously added or not.
  3. It runs the Automatic Tasks defined in the template.

Technical Details:

  1. Adding Credentials:
    1. The tool uses the AddCredential method from namespace Sdl.ProjectAutomation.FileBased to add credentials. Here’s the relevant code snippet:
      public void AddCredential(Uri uri, string credential)
      {
        if (IsTermbaseServerUri(uri) || IsProjectServerUri(uri))
        {
          GenericCredentials genericCredentials = new GenericCredentials(credential);
          WCFToken samlToken = ((genericCredentials["SamlToken"] != null) ? JsonConvert.DeserializeObject<WCFToken>(genericCredentials["SamlToken"]) : null);
          UserCredentials userCredentials = new UserCredentials(genericCredentials.UserName, genericCredentials.Password, GetUserType(genericCredentials))
          {
            SamlToken = samlToken,
            AuthToken = genericCredentials["AuthToken"],
            ExpirationDate = ((genericCredentials["Exp"] != null) ? DateTime.Parse(genericCredentials["Exp"]) : default(DateTime))
          };
          switch (userCredentials.UserType)
          {
            case UserManagerTokenType.CustomUser:
            case UserManagerTokenType.CustomWindowsUser:
              IdentityInfoCache.Default.SetCustomIdentity(StripSchemePrefix(uri), userCredentials.UserName, userCredentials.Password);
              break;
            case UserManagerTokenType.WindowsUser:
              IdentityInfoCache.Default.SetWindowsIdentity(StripSchemePrefix(uri));
              break;
            case UserManagerTokenType.Saml2User:
              IdentityInfoCache.Default.SetCustomIdentity(StripSchemePrefix(uri), userCredentials);
              break;
          }
        }
        else
        {
          _translationProviderCredentialStore.AddCredential(uri, new TranslationProviderCredential(credential, persist: false));
        }
      }
      
    2. Credentials Format:
      $"user={username};password={password};type=CustomUser"
  2. Running Automatic Tasks:
    1. The tool then executes automatic tasks using the RunAutomaticTasks method from the same namespace:
      public TaskSequence RunAutomaticTasks(Guid[] projectFileIds, string[] taskTemplateIds)
      {
          try
          {
              return RunAutomaticTasks(projectFileIds, taskTemplateIds, null, null);
          }
          catch (Exception exception)
          {
              Exception ex = ExceptionMapper.MapException(exception);
              throw ex;
          }
      }
      

Issue Description:

  1. Initially, the tool works as expected.
  2. However, when the credentials expire (usually after 8 hours), the ‘Pre-translate Files’ task fails with the following error:
    Unexpected exception when configuring file multiFileConverter for task 'Pre-translate Files':
    Failed to create an instance of translation provider 'sdltm.https://<ourSdlServer>'.
  3. This error occurs even though I re-add credentials every time a new project is created using the AddCredential method.
  4. I suspect that the cached credentials are not being updated or replaced when new credentials are added.

Request for Assistance:

I’d appreciate help with the following:

  1. Can anyone confirm whether the credential cache is updated or cleared when AddCredential is called?
  2. Is there a mechanism to:
    1. Verify if credentials have expired and update them if so.
    2. Force the system to reset the cached authentication and use the new credentials added by the tool?
    3. Any recommendations to ensure that expired credentials do not cause task failures?

Thanks in advance for your insights and suggestions! Let me know if additional details are needed.

  • Hi  ,

    If the issue is related to identifying whether or not the AddCredential function (also) updates an existing credential with the same uri.  Then why not manage that process yourself?

    Plaese make reference to Class TranslationProviderCredentialStore. It enables you to get, add, remove and clear credentials.

    Maybe first check if the credential exists for provider uri and then remove it before adding a new one?

    Example

    var myCredential = credentialStore.GetCredential(translationProviderUri);
    if (myCredential != null)
    {
        credentialStore.RemoveCredential(translationProviderUri);
    }
    
    var newCredential = new TranslationProviderCredential(credential: "credential string", persist: false);
    credentialStore.AddCredential(translationProviderUri, newCredential);

  • Thank you   for the suggestion!
    The point is that I am adding credentials in the FileBasedProject object like this:

    public void SetTMCredentialsOnly(FileBasedProject project, string username, string password, bool useWindowsSecurity = false)
    {
        var credentialStore = new TranslationProviderCredentialStore();
        var allTranslationProviders = new List<TranslationProviderCascadeEntry>();
        TranslationProviderConfiguration translationProviderConfiguration = project.GetTranslationProviderConfiguration();
        allTranslationProviders.AddRange(translationProviderConfiguration.Entries);
    
        foreach (var lang in project.GetProjectInfo().TargetLanguages)
        {
            var langProviders = project.GetTranslationProviderConfiguration(lang);
            foreach (var prov in langProviders.Entries)
            {
                // Check whether the provider has already been added
                var exists = allTranslationProviders.Any(p => p.MainTranslationProvider.Uri.ToString()
                    .Equals(prov.MainTranslationProvider.Uri.ToString()));
                if (exists)
                {
                    continue;
                }
                else
                {
                    allTranslationProviders.Add(prov);
                }
            }
        }
    
        foreach (var provider in allTranslationProviders)
        {
            Uri uri = provider.MainTranslationProvider?.Uri;
            if (!uri.ToString().StartsWith("sdltm.http"))
            {
                continue;
            }
            string type = useWindowsSecurity ? "WindowsUser" : "CustomUser";
            string credentials = $"user={username};password={password};type={type}";
            project.Credentials.AddCredential(uri, credentials);
        }
    }
    

    Key Clarification:

    • Here, I retrieve all the providers from the project template, filter only the GroupShare providers (sdltm.http*), and then add credentials using the FileBasedProject.Credentials property.
    • The credentials are passed as parameters (username, password, etc.) and added directly to the project.

    My Question:

    If I use the following line:

    var myCredential = credentialStore.GetCredential(translationProviderUri);

    Will it reference the same credential store that FileBasedProject.Credentials uses?

    I’m trying to understand if TranslationProviderCredentialStore and FileBasedProject.Credentials work with the same underlying store. If not, I might have to manage credential removal and re-adding more explicitly as you suggested.

    Thanks again for your help! 

  • Hi  ,  When you create a new instance of `TranslationProviderCredentialStore`, it operates independently and does not reference the credentials managed by the `FileBasedProject.Credentials`. This means any credentials added to your separate instance won't be recognized by the project or persisted across sessions.
    It'll only live in memory, a bit like my dream to go on vacation in Hawaii this year!

    The `FileBasedProject.Credentials` interfaces with the primary `TranslationProviderCredentialStore` managed by Trados Studio. This store is typically located in the user’s roaming directory:

    C:\Users\<YourUsername>\AppData\Roaming\Trados\Trados Studio\Studio18\TranslationProviderCredentialStore.bin#

    Trados Studio manages this store to save and load credentials, ensuring they persist and are accessible across different projects and sessions.


    Recommend

    To ensure that credentials are properly managed and persisted, In yr case I would recommend that you interact directly with the project's credential store (`FileBasedProject.Credentials`). This ensures consistency and leverages Trados Studio's built-in credential management.

    Example

    public void SetTMCredentialsOnly(FileBasedProject project, string username, string password, bool useWindowsSecurity = false)
    {
        var credentialStore = project.Credentials; // Use the project's credential store
        var allTranslationProviders = new List<TranslationProviderCascadeEntry>();
        TranslationProviderConfiguration translationProviderConfiguration = project.GetTranslationProviderConfiguration();
        allTranslationProviders.AddRange(translationProviderConfiguration.Entries);
    
        foreach (var lang in project.GetProjectInfo().TargetLanguages)
        {
            var langProviders = project.GetTranslationProviderConfiguration(lang);
            foreach (var prov in langProviders.Entries)
            {
                // Avoid adding duplicate providers
                if (!allTranslationProviders.Any(p => p.MainTranslationProvider.Uri.Equals(prov.MainTranslationProvider.Uri)))
                {
                    allTranslationProviders.Add(prov);
                }
            }
        }
    
        foreach (var provider in allTranslationProviders)
        {
            Uri uri = provider.MainTranslationProvider?.Uri;
            if (uri == null || !uri.ToString().StartsWith("sdltm.http", StringComparison.OrdinalIgnoreCase))
            {
                continue;
            }
    
            string type = useWindowsSecurity ? "WindowsUser" : "CustomUser";
            string credentials = $"user={username};password={password};type={type}";
    
            
            // Add/Update the new credential
            credentialStore.AddCredential(uri, credentials);
        }
    }

    let me know how it goes.

  • Thank you   for the detailed explanation and the suggestions!

    I’m currently using Trados 2022, and I’ve noticed that the ProjectCredentials class in:

    var credentialStore = project.Credentials;

    doesn’t provide public methods like GetCredential(uri) or RemoveCredential(uri).

    This makes it impossible to directly check for existing credentials or remove them before adding new ones.

    Do you have any recommendations or workarounds for handling this limitation in Trados 2022?

    Thanks again for your support!

  • Hi  , you're right, Just checked also for 2024 and only see AddCredential exposed for the Sdl.ProjectAutomation.FileBased.ProjectCredential as it updates the existing credential if it exists, otherwise adds a new one.

    But I don't think it's a blocker for your right? So, to answer your very first question at the beginning of this thread, will AddCredential also update it if it already exists: "Yes, for the FileBasedProject.Credentials"; RemoveCredential is not exposed from the Sdl.ProjectAutomation.FileBased.ProjectCredential

    Let me know how it goes, sorry confusion; this is also a surprise for me!

    The sample code I provided above (with get and remove) will only work for the Credential Store exposed from the Translation Provider API.

    Note: I've updated the sample provided in the prevous post to avoid confusion; thx for checking this!!! appreciated

  • Thank you   for clarifying and updating your previous post!

    Actually, I believe my issue lies in the fact that when adding credentials again, it doesn't seem to update the old credentials.

    Since I cannot remove credentials from FileBasedProject.Credentials, I’ve been using:

    var credentialStore = new TranslationProviderCredentialStore();

    This works in the sense that it retrieves credentials and allows the pre-translation task to run.

    Issue Details:

    I’ve been testing the tool by creating two projects to analyze the behavior:

    1. First Project:
      1. The tool adds credentials and authenticates correctly (throws an error if the password is wrong).
      2. It creates the project successfully, and the pre-translation is filled from the TM matches.
    2. Second Project:
      1. The tool removes the old credentials, adds new credentials (same URL and username but with a wrong password).
      2. Credentials are added without even attempting to authenticate—no error is thrown.
      3. Surprisingly, the second project is processed correctly, and the pre-translation is filled from the TM matches, even with the wrong credentials.

    I also tried your updated example and this version of the code:

    public void SetTMCredentialsOnly(FileBasedProject project, string username, string password, bool useWindowsSecurity = false)
    {
        var credentialStore = new TranslationProviderCredentialStore();
        var allTranslationProviders = new List<TranslationProviderCascadeEntry>();
        TranslationProviderConfiguration translationProviderConfiguration = project.GetTranslationProviderConfiguration();
        allTranslationProviders.AddRange(translationProviderConfiguration.Entries);
    
        foreach (var lang in project.GetProjectInfo().TargetLanguages)
        {
            var langProviders = project.GetTranslationProviderConfiguration(lang);
            foreach (var prov in langProviders.Entries)
            {
                // Check whether the provider has been added
                var exists = allTranslationProviders.Any(p => p.MainTranslationProvider.Uri.ToString()
                    .Equals(prov.MainTranslationProvider.Uri.ToString()));
                if (exists)
                {
                    continue;
                }
                else
                {
                    allTranslationProviders.Add(prov);
                }
            }
        }
    
        foreach (var provider in allTranslationProviders)
        {
            Uri uri = provider.MainTranslationProvider?.Uri;
            if (!uri.ToString().StartsWith("sdltm.http"))
            {
                continue;
            }
    
            string type = useWindowsSecurity ? "WindowsUser" : "CustomUser";
            string credentials = $"user={username};password={password};type={type}";
    
            var myCredential = credentialStore.GetCredential(uri);
            if (myCredential != null)
            {
                credentialStore.RemoveCredential(uri);
            }
    
            var newCredential = new TranslationProviderCredential(credential: credentials, persist: false);
            credentialStore.AddCredential(uri, newCredential);
        }
    }
    
    Observation:

    In both cases, the behavior remains the same: credentials are added but not authenticated when updated with the wrong password, and tasks still run as if the old credentials are being used.

    Could there be some credential caching mechanism outside the scope of what we’re managing here? This might explain why the pre-translation task succeeds even with incorrect credentials.

    Pleas let me know your thoughts or if there’s another area I should investigate!