Not verified hands-on. This article was written from primary documentation rather than reproduced in an org, so it carries no tested-release badge. If you run it and something differs, say so in the comments and it gets tested and corrected.

In one sentence: you sent a value that is not in the field’s value set, and the field has “Restrict picklist to the values defined in the value set” ticked. The message names the field: bad value for restricted picklist field: Platinum. Untick that box and the same write succeeds silently, which is the part that catches people out.

INVALID_OR_NULL_FOR_RESTRICTED_PICKLIST:
bad value for restricted picklist field: Platinum

The checkbox is the whole behaviour

A picklist field in Salesforce is stored as text. The value set is a list of what the UI offers, not a constraint on what the column can hold. The restriction checkbox is what turns the list into a constraint.

With it off, the API accepts anything that fits the field length. Your Account Rating field can hold Platinum, platinum, PLATNUM and a trailing-space variant of each, all at once, and none of them appear in the picklist when a user opens the record. The values are simply there, invisible in Setup, showing up as blank or as odd entries in report groupings.

With it on, the write fails and you get this error. That is the field doing its job.

Global value sets are always restricted

When a picklist uses a global value set rather than its own local values, the restriction is enforced and the checkbox is not yours to untick. This is a good reason to use global value sets for anything an integration writes to: the enforcement comes along automatically and stays consistent across every field that shares the set.

What this means for integrations

The pattern that causes production incidents goes like this. An integration writes to an unrestricted picklist for two years. Somebody notices the report groupings are a mess, ticks the restriction box to clean things up, and the next sync starts failing on values that were being accepted the whole time.

Nothing about the integration changed. The field started enforcing what it always described.

So before ticking the box, find out what is actually in the column:

SELECT Rating, COUNT(Id)
FROM Account
GROUP BY Rating
ORDER BY COUNT(Id) DESC

Anything in that result that is not in your value set is a row that would now fail on update, and a source system that is still sending it. Both need handling before the restriction goes on.

Mapping at the boundary

The durable fix is to translate external values into Salesforce values in one place, and to decide explicitly what happens to an unrecognised value. Reading the value set at runtime keeps the mapping honest when someone adds a value in Setup:

Set<String> allowed = new Set<String>();
for (Schema.PicklistEntry e :
        Account.Rating.getDescribe().getPicklistValues()) {
    if (e.isActive()) { allowed.add(e.getValue()); }
}

String mapped = ratingMap.get(inbound);
a.Rating = allowed.contains(mapped) ? mapped : null;

Falling back to null is one choice. Routing the record to an exception queue is usually the better one, because a silently nulled field is a data quality problem that nobody reports.

Three things that look like this but are not

  • Inactive values. A value that exists but has been deactivated is rejected on write, even though it is still stored on old records. isActive() is the check, and getPicklistValues() returns both.
  • Record type availability. A value can be in the value set and not available for the record type being written. That produces a different failure and is configured in the record type’s picklist assignment, not on the field.
  • Case and whitespace. Restricted picklist matching is exact. Hot with a trailing space is not Hot, and a CSV export is a reliable source of trailing spaces.

Multi-select picklists

The same rule applies to each value in the list, and the separator is a semicolon with no spaces around it. Red; Blue sends a second value of Blue, which fails on a restricted field and is quietly stored on an unrestricted one. Build these by joining a list rather than by string concatenation.

Verified in a Summer ’26 scratch org on 14 September 2026: Account.Industry.getDescribe().isRestrictedPicklist() returns false on a standard org, and inserting an Account with Industry = 'NotARealIndustry' succeeds. The error only appears once the restriction is switched on.

Frequently asked

Can I add the restriction to an existing field? Yes, and existing non-conforming data is left alone. It stays until something tries to update that record, at which point the write fails on a field nobody was editing.

Does the UI ever produce this error? Rarely, because the UI only offers valid values. Flows, Apex, the API and data loads are where it appears.

Is a null allowed? Yes, unless the field is also required. Restriction governs which values are valid, not whether a value is needed.

How do I find the invalid values already stored? Group by the field in SOQL or a report, then compare against the value set in Setup. The odd ones stand out immediately, usually with a row count of one or two.