本文へ移動
cccskills
無料GitHub で公開

picklist-field-integrity-issues

Use when picklist data quality has degraded: unrestricted picklists accepting garbage API values, dependent picklist relationships bypassed by integrations, record type picklist value mappings drifting out of sync, or orphaned values appearing in reports. NOT for the value-deactivation runbook or the API-name-vs-label trap — use admin/picklist-data-integrity. NOT for initial picklist creation or Global Value Set design — use admin/picklist-and-value-sets. NOT for record type configuration itself — use admin/record-types-and-page-layouts.

インストール方法を見る

含まれるファイル(7)

  • SKILL.md16.9 KB
  • references/examples.md3.6 KB
  • references/gotchas.md4.0 KB
  • references/llm-anti-patterns.md5.9 KB
  • references/well-architected.md3.5 KB
  • scripts/check_picklist_field_integrity_issues.py6.2 KB
  • templates/picklist-field-integrity-issues-template.md3.1 KB

SKILL.md(原文)

インストールする前に、エージェントに与えられる指示の中身を確認できます。

Picklist Field Integrity Issues

Use this skill when picklist data quality has degraded in a Salesforce org. This covers three systemic integrity gaps the platform does not prevent by default: unrestricted picklists silently accepting arbitrary API values, dependent picklist relationships that are only enforced in the UI, and record type picklist value mappings that drift after deployments or manual edits. If the problem is creating or designing a picklist from scratch, use picklist-and-value-sets instead.


Before Starting

Gather this context before working on anything in this domain:

  • Is the picklist restricted or unrestricted? Unrestricted picklists accept any string value via the API, even values not in the defined value set. Restricted picklists reject undefined values with INVALID_OR_NULL_FOR_RESTRICTED_PICKLIST. This distinction is the single biggest driver of picklist data integrity problems.
  • What channels write to this field? If only Lightning UI users create records, dependent picklist filtering works. If Data Loader, REST API, Bulk API, middleware, or Flows (in system context) also write records, dependent picklist rules are not enforced and any value can land in the field.
  • Are record types involved? Each record type maintains its own subset of available picklist values. After deployments, sandbox refreshes, or manual edits, these mappings can silently drift so that values appear in one record type that were only intended for another.

Core Concepts

Restricted vs Unrestricted Picklists

Every custom picklist field in Salesforce is either restricted or unrestricted. This setting is controlled by the "Restrict picklist to the values defined in the value set" checkbox on the field definition.

Unrestricted (default for many legacy fields): The API treats the field as a text field that happens to have suggested values. Any string written via SOAP API, REST API, Bulk API, or Data Loader is accepted — even if it does not match any defined value. Over time this produces orphaned values that pollute reports, break automations that check ISPICKVAL(), and confuse users who see unexpected entries.

Restricted: The API rejects any value not in the active value set. Writes fail with error code INVALID_OR_NULL_FOR_RESTRICTED_PICKLIST. Global Value Set-backed picklists are always restricted. Custom picklists can be toggled to restricted at any time, but toggling does NOT retroactively clean existing invalid data — it only prevents new violations.

Key implication: Converting an unrestricted picklist to restricted is safe for future writes but leaves historical garbage in place. You must audit and clean existing data separately.

Dependent Picklist Enforcement Gap

Dependent picklist relationships (where a controlling field filters the available values of a dependent field) are enforced only in the Lightning UI and Classic UI. They are not enforced by:

  • SOAP API / REST API / Bulk API
  • Data Loader (all modes)
  • Apex DML (unless you write custom validation)
  • Flow record-creates running in system context
  • Platform events that trigger record creation

This means any integration or automation that creates or updates records programmatically can write a dependent picklist value that violates the controlling-dependent mapping. The record saves successfully with no error. This is documented Salesforce platform behavior, not a bug.

Practical impact: Organizations that rely on dependent picklists for data segmentation (e.g., Country controls State) often discover after months of API imports that thousands of records have State values that don't belong to their Country.

Record Type Picklist Value Mapping Drift

Each record type on an object defines which picklist values are available for each picklist field. These mappings are stored in RecordType metadata and deployed via Metadata API, change sets, or SFDX.

How drift happens:

  1. Deployment gaps: A developer adds a new picklist value to the field but forgets to add it to the appropriate record type mappings. The value exists but is invisible to users of that record type.
  2. Sandbox refresh timing: A record type mapping is updated in production but the sandbox was refreshed before the change. Development continues against stale mappings.
  3. Manual Setup edits: An admin adds a value to one record type but forgets others. There is no built-in alert or audit trail for record type picklist mapping changes.
  4. Global Value Set updates: Adding a value to a GVS makes it available on the field, but it is NOT automatically added to any record type mapping. Admins must manually add it to each record type that should see it.

Detection is hard: The platform does not surface "this value exists on the field but is not mapped to any record type" as a warning. The only way to find drift is to compare the field's value set against each record type's mapping — either manually in Setup or programmatically via the Metadata API or UI API.


Common Patterns

Pattern 1: Audit and Restrict an Unrestricted Picklist

When to use: An unrestricted picklist has accumulated invalid values from API writes or imports and you need to clean it up and prevent future violations.

How it works:

  1. Query all distinct values currently in the field:
    SELECT Status__c, COUNT(Id) FROM Case GROUP BY Status__c
    
  2. Compare the query results against the defined picklist values (via Setup or Metadata API retrieve of the CustomField)
  3. For each invalid value, decide: replace with a valid value, or set to null
  4. Use Data Loader or an Apex batch to update records carrying invalid values
  5. Toggle the field to Restricted in Setup (Object Manager > Field > Edit > check "Restrict picklist to the values defined in the value set")
  6. Test that API writes of invalid values now fail with INVALID_OR_NULL_FOR_RESTRICTED_PICKLIST

Why not skip the audit: Toggling to restricted without cleaning data first leaves orphaned values on existing records. Reports still show the garbage. ISPICKVAL() checks in formulas and validation rules may not handle the unexpected values correctly.

Pattern 2: Enforce Dependent Picklist Rules at the Data Layer

When to use: Dependent picklist relationships must hold even for records created via API or integration.

How it works:

  1. Document the controlling-dependent value matrix (Setup > Object Manager > [Dependent Field] > Field Dependencies)

  2. Build a validation rule or before-insert/before-update Apex trigger that enforces the mapping:

    // Validation rule approach (for simple mappings)
    // Error condition: Country is "United States" but State is not a valid US state
    AND(
      ISPICKVAL(Country__c, "United States"),
      NOT(
        OR(
          ISPICKVAL(State__c, "California"),
          ISPICKVAL(State__c, "New York"),
          ISPICKVAL(State__c, "Texas")
        )
      )
    )
    
  3. For complex matrices, use a Custom Metadata Type to store the valid combinations and an Apex trigger to validate against it

  4. Test via API to confirm invalid combinations are now rejected

Why not the alternative: Relying on the UI-only enforcement is invisible — you will not know records are being created with invalid combinations until a report or downstream process breaks.

Pattern 3: Detect and Fix Record Type Picklist Value Mapping Drift

When to use: After a deployment, sandbox refresh, or manual edit, you suspect record type picklist mappings are out of sync with the intended configuration.

How it works:

  1. Retrieve the RecordType metadata for the object via Metadata API or SFDX:
    sf project retrieve start --metadata RecordType:Account.Enterprise
    
  2. In the retrieved XML, examine the <picklistValues> blocks. Each block lists which values are active for that record type on that field.
  3. Compare against the field's full value set (from the CustomField metadata or GlobalValueSet metadata)
  4. Identify values that are:
    • On the field but not mapped to any record type (invisible to all users)
    • Mapped to a record type but inactive on the field (silently ignored)
    • Mapped inconsistently across record types (unintentional)
  5. Fix by updating the record type metadata and redeploying, or manually via Setup > Record Types > Picklists Available for Editing

Why not manual-only: With 5+ record types and 20+ picklist fields, manual comparison in Setup is error-prone and does not scale. A scripted approach catches drift that humans miss.


Decision Guidance

SituationRecommended ApproachReason
Unrestricted picklist with known API consumersAudit existing data, then toggle to restrictedPrevents future garbage; one-time cleanup for historical data
Unrestricted picklist but cannot break existing integrationsAdd validation rule instead of restrictingValidation rules return actionable errors; restriction returns a generic error code
Dependent picklist with API/integration writesAdd validation rule or Apex trigger to enforce mappingUI-only enforcement leaves a data quality gap for all non-UI channels
Simple dependent mapping (< 20 combinations)Validation rule with ISPICKVALNo code; declarative; easy to maintain
Complex dependent mapping (50+ combinations)Custom Metadata Type + Apex triggerScales without hardcoding; deployable across environments
Record type picklist drift suspectedScript a metadata retrieve and compareManual Setup audit does not scale beyond a few record types
New value added to Global Value SetManually add to each record type that needs itGVS value additions are NOT auto-mapped to record types

Recommended Workflow

Step-by-step instructions for an AI agent or practitioner activating this skill:

  1. Identify the integrity issue category — Determine whether the problem is unrestricted picklist pollution, dependent picklist bypass, record type mapping drift, or a combination. Query the field to see what values actually exist in data versus what the value set defines.
  2. Gather field metadata — Retrieve the CustomField or GlobalValueSet definition to confirm restricted/unrestricted status, the active value set, and any dependent picklist configuration. Check how many record types exist and whether they have divergent picklist mappings.
  3. Audit current data — Run a GROUP BY SOQL query on the affected field to identify all distinct values and their record counts. Flag any value that does not appear in the active value set as an orphan.
  4. Design the remediation — For orphaned values: decide replace or null. For dependent picklist bypass: draft a validation rule or Apex trigger. For record type drift: prepare updated metadata. Use the templates in this skill package.
  5. Implement and test — Apply the fix in a sandbox. Test that invalid API writes are now rejected. Confirm that valid UI and API operations still succeed. Verify record type mappings are consistent.
  6. Clean historical data — Run Data Loader or Apex batch updates to fix existing records that carry invalid values. Verify with a re-run of the audit query.
  7. Document and monitor — Record what was fixed and why. Set up a scheduled report or dashboard to surface any new orphaned values (a canary for regression).

Review Checklist

Run through these before marking work in this area complete:

  • Confirmed whether each affected picklist is restricted or unrestricted
  • Queried actual field values and compared against the defined value set
  • Orphaned/invalid values identified with record counts
  • Data cleanup plan documented (replace vs null for each invalid value)
  • For dependent picklist issues: validation rule or trigger deployed and tested via API
  • For record type drift: all record type mappings reviewed and corrected
  • Restricted flag toggled where appropriate (after data cleanup)
  • Downstream impacts checked: validation rules, flows, formulas, reports, dashboards
  • Monitoring mechanism in place (scheduled report or periodic audit query)

Salesforce-Specific Gotchas

Non-obvious platform behaviors that cause real production problems:

  1. Toggling to restricted does not clean existing data — When you check "Restrict picklist to the values defined in the value set," Salesforce only enforces the restriction on future writes. All existing records keep their current values, even if those values are not in the defined value set. You must clean historical data separately.

  2. Global Value Set values are not auto-added to record type mappings — Adding a new value to a Global Value Set makes it available on the field definition, but it does NOT automatically appear in any record type's picklist mapping. Admins must manually add the value to each record type. This is the most common source of "I added the value but users can't see it" tickets.

  3. Dependent picklist with no mapped values shows ALL values — If a controlling value has zero dependent values mapped in the dependency matrix, the dependent picklist shows the entire value set — not an empty list. This is the opposite of what admins expect and silently undermines the filtering intent.

  4. API-created records bypass dependent picklist validation silently — Records created via API, Data Loader, or Bulk API with invalid controlling-dependent combinations save without any error or warning. There is no after-the-fact flag on the record indicating it violated the dependency. The only way to detect this is to query and cross-check.

  5. Inactive values on restricted picklists still exist on records — Deactivating a value on a restricted picklist prevents future selection but does not remove it from existing records. If you then query for that value, records still appear. If you try to update such a record without changing the picklist value, the save succeeds (the platform does not re-validate unchanged fields). But if you try to set the field to the same inactive value on a new record, it fails.


Output Artifacts

ArtifactDescription
Picklist Integrity Audit ReportList of all orphaned/invalid values per field with record counts and recommended action
Remediation PlanStep-by-step cleanup instructions: data updates, restriction toggles, validation rules, and record type mapping fixes
Dependent Picklist Enforcement TemplateValidation rule or Apex trigger template that enforces the controlling-dependent mapping at the data layer

Related Skills

  • picklist-and-value-sets — use for initial picklist design, Global Value Set creation, and standard value management; this skill picks up where that one ends when data quality has degraded
  • record-types-and-page-layouts — use for record type configuration; this skill covers the specific problem of record type picklist value mapping drift
  • large-scale-deduplication — use when picklist integrity issues are part of a broader data quality remediation effort

レビュー

まだレビューはありません。使ってみた感想をお寄せください。

同じリポジトリのスキル

概要と使いどころ

Use this skill when writing test-first, behavior-driven acceptance criteria in Given/When/Then format for a Salesforce user story. Covers happy path, edge cases, negative paths, permission boundaries, and data-state preconditions so the AC block can drive UAT scripts and Apex test design downstream. Trigger keywords: given when then, gherkin, behavior driven AC, test first acceptance criteria, scenario outline, BDD acceptance criteria. NOT for the user-story format itself (use admin/user-story-writing-for-salesforce). NOT for UAT script writing (use admin/uat-test-case-design). NOT for Apex test method generation (use agents/test-class-generator). NOT for high-level UAT planning (use admin/uat-and-acceptance-criteria). More triggers: acceptance criteria record, ac_id, req_id on a criterion, artefact under test, negative case for a rule-type requirement, no-match fall-through criterion, oracle for a Then clause, test type apex flow manual, criteria linter, check_ac_format.py, --manifest-dir.

日本語の概要は準備中です。原文の説明を表示しています。

PranavNagrecha/AwesomeSalesforceSkills192026年10月4日 更新

Task and Event objects: polymorphic WhatId/WhoId, Activity object model, ActivityHistory vs OpenActivity, activity timeline customization, bulk task creation, Einstein Activity Capture boundaries. NOT for turning on EAC or calendar sync — use admin/einstein-activity-capture-setup. NOT for Email-to-Case — use admin/case-management-setup. Covers ActivitiesSettings metadata, enableActivities, shared Task/Event custom fields and FLS, TaskStatus value sets, Shared Activities and TaskRelation/EventRelation, recurring and child activities, and partial-success bulk DML on Task.

日本語の概要は準備中です。原文の説明を表示しています。

PranavNagrecha/AwesomeSalesforceSkills192026年10月4日 更新

Design Invocable Apex actions that return deterministic, agent-friendly errors instead of surfacing raw exceptions to the LLM. NOT for authoring the action itself — @InvocableMethod schema, labels, security context — use agentforce/custom-agent-actions-apex. NOT for the Apex tests that force each error branch — use agentforce/agent-action-unit-tests.

日本語の概要は準備中です。原文の説明を表示しています。

PranavNagrecha/AwesomeSalesforceSkills192026年10月4日 更新

Use when designing how an Agentforce agent extracts structured input parameters (slots) from a user's natural-language utterance to invoke an action. Triggers: 'agent extract date from user', 'agent action argument extraction', 'agentforce slot filling', 'agent invocable input mapping', 'agent fails to fill required parameter'. NOT for action authoring (use agentforce/agent-actions) or for prompt-template variable binding (use agentforce/prompt-builder-templates).

日本語の概要は準備中です。原文の説明を表示しています。

PranavNagrecha/AwesomeSalesforceSkills192026年10月4日 更新

Apex test patterns for @InvocableMethod agent actions: per-reason-code branch coverage, bulk safety, callout mocking, deterministic assertions. NOT for testing whether the agent routes to the right topic or answers well — use agentforce/agent-testing-and-evaluation. NOT for designing the error envelope the tests assert on — use agentforce/agent-action-error-handling.

日本語の概要は準備中です。原文の説明を表示しています。

PranavNagrecha/AwesomeSalesforceSkills192026年10月4日 更新

Designing or reviewing Agentforce actions: Flow actions, Apex invocable actions, prompt-template actions, action naming, input and output contracts, confirmation requirements, and safe error behavior. Triggers: 'agent actions', 'build an agent that can look up an order', 'make the agent able to check order status', 'give the agent a capability', 'agent that can retrieve a record', 'flow action for agent', 'agent invocable action', 'action schema design'. NOT for writing the Apex class itself — use agentforce/custom-agent-actions-apex. NOT for the reason_code error envelope that stops an agent retry loop — use agentforce/agent-action-error-handling.

日本語の概要は準備中です。原文の説明を表示しています。

PranavNagrecha/AwesomeSalesforceSkills192026年10月4日 更新

PranavNagrecha のスキルをすべて見る

このスキルの問題を報告する