I have a batch class:

    public class DataValidation implements Database.Batchable<sObject>, Database.AllowsCallouts{
    private List<String> missingDates;
    public DataValidation(List<String> missingDates) {
        this.missingDates = missingDates;
    public Database.QueryLocator start(Database.BatchableContext bc) {

    public void execute(Database.BatchableContext bc, List<Exchange_Rate__c> listExistingExchangeRates){
        listNewRecords = CurrencyExchangeService.makeCircularRequest(missingDates);
        upsert listNewRecords;

    public void finish(Database.BatchableContext bc){

    public class MetadataUtility {
    public static void setNewCustomField() {
        List<String> listNewFieldsCurrencies = CurrencyExchangeService.getNewFields();
        if(listNewFieldsCurrencies.size() > 0){
    private static void generateField(List<String> listFieldCurrencies){
        for(String field : listFieldCurrencies){
            String metadata = '{"Metadata" : {"type" : "Currency","precision" : 18,"scale" : 1,"label" : "' +
                              + field + '","required" : false},"fullName" : "Exchange_Rate__c.'+field+'__c"}';
    private static String createField(String metadata) {
        HttpRequest request = new HttpRequest();
        request.setHeader('Authorization','Bearer {!$Credential.OAuthToken}');
        request.setHeader('Content-Type', 'application/json');
        Http http = new Http();
        HTTPResponse res = http.send(request);
        return res.getBody();

If there is a new value in the picklist, setNewCustomField() adds a new field to the custom object. Next, makeCircularRequest() makes a request to an external service and returns a List <Exchange_Rates__с>. But sometimes I get an error. As far as I was able to find out, it is due to the fact that setNewCustomField() does not always have time to add a new field, and the response is already beginning to be written to the corresponding fields of my object and the system does not find a new field and throws an error. If I am right, is it possible to avoid this?

1 Answer 1


Metadata Deployment is always asynchronous and won't be complete in time for the next statement in your batchable's execute()

Each metadata api deployment must configure a callback class that will get invoked when the deployment finishes. Thus, do your follow-on processing when the callback's handleResult method is invoked.

I don't fully understand your business use case but you're going to have to decouple updating the metadata from any logic that depends on that updated metadata.

  • I have added a class code that adds a new field. I think I'm adding a new field in a different way, not like in the example on your link. Otherwise, unfortunately, I did not understand how to achieve a callback... Could you explain in more detail? Jun 26, 2021 at 13:13
  • ah -- you are using the Tooling API. So are you saying that when the HTTP send() returns the next statement doesn't find the newly-created field? If you do a describe() on the Exchange_Rate__c after the Http send() - the new field doesn't exist? You may need to delegate the reference to the new fields to a queueable
    – cropredy
    Jun 26, 2021 at 18:52
  • Yes, that's right... I also moved the link to create a new field to the queue and so far everything is working. I hope that my problem has been solved. Thank you for your help! Jun 27, 2021 at 12:47
  • It turned out that when I start the queue, I get the error " Callout from scheduled Apex not supported." Therefore, I still won't be able to add a new field and fill it in when starting the task... Jun 30, 2021 at 14:11
  • 1
    did you include implements Database.AllowCallouts on your queueable class?
    – cropredy
    Jun 30, 2021 at 18:33

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .