0

I've come across an error where the Bulk API and the Rest API differ in their behavior when inserting records with record types. To sum up the problem:

Suppose one or more custom record types are defined on an object, and the user has permission to use all custom record types, in addition to the Master record type. Why does the Rest API allow insertion of records with the Master record type, but the Bulk API returns an error for them?

Is this a bug in the API, or is it behaving as designed? There does not appear to be any documentation or open questions regarding this behavior.

Example

To illustrate the point, I've defined two record types on the Account object—Customer and Partner.

Profile and Permission Set Setup

The user performing the insertion has the following permissions:

  1. --Master-- is selected for the record type on the user profile; and
  2. Both Customer and Partner record types are assigned via a permission set.

This is confirmed in How is record type access specified?, this enables the creation of records (Accounts) with one of three Record Types: Customer, Partner, and Master.


user profile

user permission set


Rest API Insertion

The REST API happily inserts three Accounts with all possible record types:

SESSION_ID='MY-SESSION-ID'
INSTANCE_URL=https://MY-INSTANCE.salesforce.com

# Create account with `Master` record type.
curl -H "Authorization: Bearer $SESSION_ID" -H 'Content-Type: application/json' $INSTANCE_URL/services/data/v48.0/sobjects/Account/ -d '{ "Name": "REST API account, record type = Master" }'

# Create account with `Partner` record type.
curl -H "Authorization: Bearer $SESSION_ID" -H 'Content-Type: application/json' $INSTANCE_URL/services/data/v48.0/sobjects/Account/ -d '{ "Name": "REST API account, record type = Partner", "RecordTypeId": "0126g000000kq3rAAA" }'

# Create account with `Customer` record type.
curl -H "Authorization: Bearer $SESSION_ID" -H 'Content-Type: application/json' $INSTANCE_URL/services/data/v48.0/sobjects/Account/ -d '{ "Name": "REST API account, record type = Customer", "RecordTypeId": "0126g000000kq3wAAA" }'

Bulk API

Performing the same insertion with the Bulk API however, yields a different result:

# Create a job.
curl -H "X-SFDC-Session: $SESSION_ID" -H 'Content-Type: application/xml' $INSTANCE_URL/services/async/48.0/job --data-binary @- <<EOF
<?xml version="1.0" encoding="UTF-8"?>
<jobInfo xmlns="http://www.force.com/2009/06/asyncapi/dataload">
    <operation>insert</operation>
    <object>Account</object>
    <contentType>CSV</contentType>
</jobInfo>
EOF

# Add a batch to the job.
# NOTE: Substitute the job id returned in previous command.
curl -H "X-SFDC-Session: $SESSION_ID" -H 'Content-Type: text/csv' $INSTANCE_URL/services/async/48.0/job/7506g000004Jih3AAC/batch --data-binary @- <<EOF
Name,RecordTypeId
"Bulk API account, record type = Master",#N/A
"Bulk API account, record type = Partner",0126g000000kq3rAAA
"Bulk API account, record type = Customer",0126g000000kq3wAAA
EOF

# Close the job.
# NOTE: Substitute the job id.
curl -H "X-SFDC-Session: $SESSION_ID" -H 'Content-Type: application/xml' $INSTANCE_URL/services/async/48.0/job/7506g000004Jih3AAC --data-binary @- <<EOF
<?xml version="1.0" encoding="UTF-8"?>
<jobInfo xmlns="http://www.force.com/2009/06/asyncapi/dataload">
  <state>Closed</state>
</jobInfo>
EOF

# Get batch results.
# NOTE: Substitute the job id _and_ the batch id returned in second command.
curl -H "X-SFDC-Session: $SESSION_ID" $INSTANCE_URL/services/async/48.0/job/7506g000004JigZAAS/batch/7516g0000046ci9AAA/result

The error returned indicates that the one account which failed to insert is the one with the master record type:

"Id","Success","Created","Error"
"","false","false","INVALID_CROSS_REFERENCE_KEY:Record Type ID: this ID value isn't valid for the user: :RecordTypeId --"
"0016g00000Db9ykAAB","true","true",""
"0016g00000Db9ylAAB","true","true",""
0

Solution found!

Apparently the problem was in one small tweak to the batch CSV. Notice the use of a blank string rather than #N/A for the first row's RecordTypeId:

curl -H "X-SFDC-Session: $SESSION_ID" -H 'Content-Type: text/csv' $INSTANCE_URL/services/async/48.0/job/7506g000004Jih3AAC/batch --data-binary @- <<EOF
Name,RecordTypeId
"Bulk API account, record type = Master",
"Bulk API account, record type = Partner",0126g000000kq3rAAA
"Bulk API account, record type = Customer",0126g000000kq3wAAA
EOF

It seems that the Bulk API rejects records with RecordTypeId explicitly set to #N/A in the presence of custom record types available to the user. While the rationale behind this is not clear, it is at least consistent with the Rest API's behavior if the RecordTypeId is explicitly set to null,

curl -H "Authorization: Bearer $SESSION_ID" -H 'Content-Type: application/json' $INSTANCE_URL/services/data/v48.0/sobjects/Account/ -d '{ "Name": "REST API account, record type = Partner", "RecordTypeId": null }'

# Returns:
#
# [{"message":"Record Type ID: this ID value isn't valid for the user: ","errorCode":"INVALID_CROSS_REFERENCE_KEY","fields":["RecordTypeId"]}]

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.