I would love to be able to upsert records to automate some data creation for a forecasting module, specifically Opportunity and OpportunityLineItem records. But I am becoming convinced that it is not possible to do so.

When I try with the PricebookEntryId field specified on records I know don't exist yet, I still get this error:

Unable to create/update fields: PricebookEntryId. Please check the security settings of this field and verify that it is read/write for your profile or permission set.

However, if I remove it, I obviously get:

System.DmlException: Upsert failed. First exception on row 0; first error: FIELD_INTEGRITY_EXCEPTION, field integrity exception: PricebookEntryId, unknown (versions 3.0 and higher must specify pricebook entry id, others must specify product id): [PricebookEntryId, unknown]

Seems like I'm stuck between a rock and a hard place. The way I see it, my only options are to:

  • Delete every forecasting OpportunityLineItem in the system before running the calculation
  • Query all the existing records before doing my upsert, then either:
    • Separate the insert/update, and remove PricebookEntryId for existing records
    • Use a Map to store existing records, and never add them to the insert collection

None of these approaches are ideal. They add a lot of complexity for what seems like a simple roadblock. Is it really impossible to upsert the OpportunityLineItem object?

  • I recall trying this once and failed as did you; I use a delete all and replace strategy which has interesting side effects on the Opportunity Field History as the Opportunity.Amount goes from nn.nn to zero and then back up to mm.mm. Admittedly, my use case was sync'ing line items from one object to Opportunity, not a mass recalculation
    – cropredy
    Jan 26, 2017 at 5:27

1 Answer 1


I've done it before by not setting the PricebookEntryId field and setting it in a Before Insert trigger (you may need to ensure this is the first code the inserted OrderLineItem recs encounter!)

The updates work because you're not setting the field and the inserts work because you set the field in a Before Insert trigger.

Here's a ridiculous example, but you could pass through enough info in custom field(s) in order to work out the correct PriceBookEntryId.

trigger MyOLITrigger on OpportunityLineItem (before insert){
    if (Trigger.IsBefore && Trigger.IsInsert)
        for (OpportunityLineItem oli : Trigger.New)
            if (oli.PriceBookEntryId==null){
                oli.PriceBookEntryId = '01u58000001adHDAAY';
  • Clever. I'll try it out.
    – Adrian Larson
    Feb 2, 2017 at 21:37
  • 1
    I think in this case I'll just populate the Id itself to a separate field.
    – Adrian Larson
    Feb 3, 2017 at 22:54

You must log in to answer this question.

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