Skip to main content
Solved

Shopify 2025R2 Stock Item sync Customization Error: Missing type map configuration or unsupported mapping.Mapping types:ProductDataGQL -> ProductSetInputPX.Commerce.Shopify.API.GraphQL.ProductDataGQL -> PX.Commerce.Shopify.API.GraphQL.ProductSetInput

  • December 24, 2025
  • 4 replies
  • 67 views

vivekm
Varsity III
Forum|alt.badge.img

Hello Everyone,

I am working with Build 2025R2 Version 25.200.0248 Shopify Connector.

I have customized Stock Item sync processor and overridden SaveBucketExport() method (copy pasted base code only) but during product sync, getting error as: Missing type map configuration or unsupported mapping.Mapping types:ProductDataGQL -> ProductSetInputPX.Commerce.Shopify.API.GraphQL.ProductDataGQL -> PX.Commerce.Shopify.API.GraphQL.ProductSetInput.

 

Sharing sample code below, can you please review and suggest possible root cause and fix.

public class TestStockItemSync : PXGraphExtension<SPStockItemProcessor>
{
    public static bool IsActive() { return true; }

    #region Mapper
    private IMapper mapper;
    protected IMapper Mapper => mapper ?? (mapper = CreateMapper());
    protected virtual bool UseAutoMapper => true;
    private IMapper CreateMapper()
    {
        if (!UseAutoMapper)
        {
            throw new ApplicationException("The processor " + GetType().FullName + " must override UseAutoMapper property.");
        }

        return new MapperConfiguration(AddConfigurations).CreateMapper();
    }
    private void AddConfigurations(IMapperConfigurationExpression config)
    {
        AddAutoMapperMappings(config);
        AddAutoMapperExtraMappings(config);
    }
    protected virtual void AddAutoMapperMappings(IMapperConfigurationExpression config) { }
    protected virtual void AddAutoMapperExtraMappings(IMapperConfigurationExpression config) { }
    #endregion

    protected IProductGQLDataProvider ProductGQLDataProvider { get; set; }
    [InjectDependency]
    protected ISPGraphQLAPIClientFactory ShopifyGraphQLClientFactory { get; set; }
    [InjectDependency]
    protected ISPGraphQLDataProviderFactory<IProductGQLDataProvider> ProductGraphQLDataProviderFactory { get; set; }

    public delegate Task InitialiseDelegate(IConnector iconnector, ConnectorOperation operation, CancellationToken cancellationToken);
    [PXOverride]
    public async Task Initialise(IConnector iconnector, ConnectorOperation operation, CancellationToken cancellationToken, InitialiseDelegate BaseMethod)
    {
        await BaseMethod(iconnector, operation, cancellationToken);
        var graphQLClient = ShopifyGraphQLClientFactory.GetClient(Base.GetBindingExt<BCBindingShopify>());
        ProductGQLDataProvider = ProductGraphQLDataProviderFactory.GetProvider(graphQLClient, Mapper);
    }

    public delegate Task SaveBucketExportDelegate(SPStockItemEntityBucket bucket, IMappedEntity existing, String operation, CancellationToken cancellationToken);
    [PXOverride]
    public async Task SaveBucketExport(SPStockItemEntityBucket bucket, IMappedEntity existing, String operation, CancellationToken cancellationToken, SaveBucketExportDelegate BaseMethod)
    {
        MappedStockItem obj = bucket.Product;
        ProductDataGQL product = null;
        if (obj.Extern.Categories?.Count > 0 && Base.GetBindingExt<BCBindingShopify>()?.CombineCategoriesToTags == BCSalesCategoriesExportAttribute.SyncToProductTags)
        {
            obj.Extern.Tags = Enumerable.Concat(obj.Extern.Categories, obj.Extern.Tags ?? []);
        }
        try
        {
            product = await ProductGQLDataProvider.ProductSetAsync(obj.Extern, cancellationToken);
            if (obj.ExternID is null)
            {
                obj.Extern.Id = product.Id;
                obj.Extern.Variants.First().Id = product.Variants.First().Id;
            }
            else
            {
                var externallyStoredVariantSKUs = obj.Extern.Variants.Select(variant => variant.Sku).ToHashSet();
                var notExistedVariantIds = bucket.VariantMappings.Where(x => !externallyStoredVariantSKUs.Contains(x.Key)).Select(x => x.Value).ToList();
                if (notExistedVariantIds.Count > 0)
                    await ProductGQLDataProvider.DeleteProductVariantsBulkAsync(obj.ExternID, notExistedVariantIds, cancellationToken);
            }

            ProductDataGQL updatedProduct = await ProductGQLDataProvider.UpdateProductVariantsBulkAsync(obj.Extern, cancellationToken);
            product = updatedProduct ?? product;
            //await PublishUnpublishProduct(obj.Extern, cancellationToken);
        }
        catch (Exception ex)
        {
            throw new PXException(ex.Message);
        }

        DateTime productTimestamp = product.UpdatedAt ?? DateTime.Now;
        obj.AddVariantToDetails();
        obj.AddExtern(product, product.GetNumericId(), product.Title, productTimestamp.ToDate(false));
        await Base.SaveImages(product, obj, obj.Local?.FileURLs, cancellationToken);
        Base.UpdateStatus(obj, operation);
    }
}

Best answer by gabrielpaz86

Hi ​@vivekm,

 

Why the error is happening?

This error is usually related to AutoMapper configuration rather than the GraphQL call itself.

In the Shopify connector, the DTO (ProductDataGQL) is converted into the GraphQL mutation object (ProductSetInput) using AutoMapper. When ProductGQLDataProvider.ProductSetAsync is executed, the first step is exactly this mapping from ProductDataGQLProductSetInput.

For Stock Item sync, this mapping is normally provided by ProductProfile, which is registered in SPProductProcessor.AddAutoMapperMappings. Since you mentioned that you overrode SaveBucketExport() (and likely AddAutoMapperMappings as well), the default profile registration is no longer being applied.

Because of that, AutoMapper cannot find the mapping and throws the “Missing type map configuration” error.

 

Recommended Fix:

Make sure the ProductProfile is explicitly registered in your overridden AddAutoMapperMappings method, for example:

protected virtual void AddAutoMapperExtraMappings(IMapperConfigurationExpression config) => config.AddProfile<ProductProfile>();

This restores the default mappings between ProductDataGQL and the GraphQL mutation objects and should resolve the issue.

Hope this helps, and let us know if you still run into issues! 😊

4 replies

Forum|alt.badge.img+3

Hello, have you looked here?
Configuration may be missing.
OR you can try with this:

Override and call base implementation:

protected override void AddAutoMapperMappings(IMapperConfigurationExpression config)
{
base.AddAutoMapperMappings(config);
}

protected override void AddAutoMapperExtraMappings(IMapperConfigurationExpression config)
{
base.AddAutoMapperExtraMappings(config);
}

I hope it helps.


vivekm
Varsity III
Forum|alt.badge.img
  • Author
  • Varsity III
  • December 26, 2025

Hi Abhishek,

Thank you for the response. 

I tried to implement the suggestion but getting error in response that no suitable method found for override.

 


gabrielpaz86
Acumatica Employee
Forum|alt.badge.img+1
  • Acumatica Employee
  • Answer
  • December 29, 2025

Hi ​@vivekm,

 

Why the error is happening?

This error is usually related to AutoMapper configuration rather than the GraphQL call itself.

In the Shopify connector, the DTO (ProductDataGQL) is converted into the GraphQL mutation object (ProductSetInput) using AutoMapper. When ProductGQLDataProvider.ProductSetAsync is executed, the first step is exactly this mapping from ProductDataGQLProductSetInput.

For Stock Item sync, this mapping is normally provided by ProductProfile, which is registered in SPProductProcessor.AddAutoMapperMappings. Since you mentioned that you overrode SaveBucketExport() (and likely AddAutoMapperMappings as well), the default profile registration is no longer being applied.

Because of that, AutoMapper cannot find the mapping and throws the “Missing type map configuration” error.

 

Recommended Fix:

Make sure the ProductProfile is explicitly registered in your overridden AddAutoMapperMappings method, for example:

protected virtual void AddAutoMapperExtraMappings(IMapperConfigurationExpression config) => config.AddProfile<ProductProfile>();

This restores the default mappings between ProductDataGQL and the GraphQL mutation objects and should resolve the issue.

Hope this helps, and let us know if you still run into issues! 😊


vivekm
Varsity III
Forum|alt.badge.img
  • Author
  • Varsity III
  • January 3, 2026

Hi ​@gabrielpaz86,

Thank you for the response, the suggested recommendation is working as expected.