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 theMaster
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:
--Master--
is selected for the record type on the user profile; and- Both
Customer
andPartner
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
.
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",""