Metadata API error while reading Picklist: Web service callout failed: Unable to find apex schema info

This is a very similar scenario to what is occurring in Tooling API in Apex - polymorphism, generic query() callout? and is caused by an underlying limitation in Wsdl2Apex and WebServiceCallout.invoke().

The Metadata API readMetadata web method returns a generic ReadResult with records of type tns:Metadata:

<xsd:complexType name="ReadResult">
 <xsd:sequence>
  <xsd:element name="records" minOccurs="0" maxOccurs="unbounded" type="tns:Metadata"/>
 </xsd:sequence>
</xsd:complexType>

Which is fine, except in this case you don't get tns:Metadata records back. You get tns:CustomField records back that are an extension of tns:Metadata and include a sequence of elements specific to custom fields.

WebServiceCallout.invoke doesn't know how to unpack the specific CustomField complex type when it was just expecting Metadata.

Instead, you need to create a classes to do this and then utilize them in a dedicated version of the readMetadata method.

It looks like you are using the apex-mdapi implementation here for readMetadata. This attempts to overcome the limitation above by passing in target metadata type with the type_x parameter and then adjusting the final infoArray parameter on WebServiceCallout.invoke to have a response type that matches what will come back from the WebService.

This will be a readCustomFieldResponse_element in your case and the corresponding ReadCustomFieldResult.

This is the point where I believe the issue is. Your CustomField needs to match that of your current API version. Each element that comes back needs to have a corresponding propertyName_type_info.


Taken from Issue # 225 on their repo. Error occurred when obtaining a custom picklist fields CustomValue.

Error:

System.CalloutException: Web service callout failed: Unable to find apex schema info

Fresh install looked like this:

public virtual class CustomValue extends Metadata {
    public String color;
    public Boolean default_x;
    public String description;
    public Boolean isActive;
    public String label;
 }

Replacement code should look something like this (you can edit it as needed):

public virtual class CustomValue extends Metadata {
    public String type = 'CustomValue';
    public String fullName;
    private String[] fullName_type_info = new String[]{'fullName',API_END,null,'0','1','false'};
    public String color;
    public Boolean default_x;
    public String description;
    public Boolean isActive;
    public String label;
    private String[] color_type_info = new String[]{'color',API_END,null,'0','1','false'};
    private String[] default_x_type_info = new String[]{'default',API_END,null,'1','1','false'};
    private String[] description_type_info = new String[]{'description',API_END,null,'0','1','false'};
    private String[] isActive_type_info = new String[]{'isActive',API_END,null,'0','1','false'};
    private String[] label_type_info = new String[]{'label',API_END,null,'0','1','false'};
    private String[] apex_schema_type_info = new String[]{API_END,'true','false'};
    private String[] field_order_type_info = new String[]{'fullName','color','default_x','description','isActive','label'};
 }

Steps:

  1. Replace the class CustomValue with the above code.
  2. Replace API_END with SOAP_M_URI