In this Blog Post, you will learn how to handle restricted picklist fields in Salesforce Agentforce using explicit action descriptions, synonym mapping, and Flow validation logic to prevent runtime execution errors.
Solving Agentforce Picklist Validation Errors: Agent Prompting & Flow Logic
Salesforce Agentforce uses Large Language Models (LLMs) to dynamically determine user intent and invoke underlying backend capabilities such as Salesforce Flows or Apex actions. However, when an Agentforce action interacts with a Restricted Picklist field, minor natural language discrepancies—such as casing, synonyms, or invalid values—will cause a FIELD_INTEGRITY_EXCEPTION error during Flow execution.
To build robust AI agents, technical architects and developers must implement a dual-layer validation strategy: defining strict prompt constraints in the Agent Action definition while enforcing validation checks inside the backend Flow.
The Challenge with Restricted Picklists in AI Agents
Standard picklist fields accept unmapped API values if unrestricted, but Restricted Picklists strictly reject any string that does not match an exact active API name.
When users interact with an AI Agent, they rarely use precise API names. For instance:
- A user says: “Set this issue as urgent.”
- The target picklist expects:
"High"
If Agentforce passes "urgent" directly to a Flow that attempts an Update Records element on a restricted picklist, the transaction fails.
Dual-Layer Defense Architecture
To solve this, implement validation at two distinct layers:
- Agent Definition Layer (Prompt & Synonym Mapping): Direct the LLM using granular input parameter descriptions, listing allowed values, mapping common synonyms, and defining strict fallback instructions when user input is ambiguous.
- Flow Engine Layer (Execution Logic): Perform an explicit decision check inside the invoked Flow before executing the record update.
Agent Definition Implementation
Below is the Agent Definition (YAML) configuration establishing strict instruction boundaries for the casePriority input parameter when updating a Case record.
system:
instructions: |
You are an AI Agent.
messages:
welcome: |
Hi, I'm Agentforce! How can I help?
error: "Something went wrong. Try again."
config:
agent_label: "Agentforce Employee Agent"
agent_template: "EmployeeCopilot__AgentforceEmployeeAgent"
developer_name: "Agentforce_Employee_Agent"
agent_type: "AgentforceEmployeeAgent"
description: "Automate common business tasks and assist users in their flow of work."
language:
default_locale: "en_US"
additional_locales:""
all_additional_locales: False
adaptive: True
knowledge:
rag_feature_config_id: ""
citations_url: ""
citations_enabled: False
start_agent agent_router:
label: "Agent Router"
description: "Welcome the user and determine the appropriate subagent based on user input"
model_config:
model: "model://sfdc_ai__DefaultEinsteinHyperClassifier"
reasoning:
instructions: ->
| Select the best tool to call based on conversation history and user's intent.
actions:
go_to_Case_Management: @utils.transition to @subagent.Case_Management
subagent Case_Management:
label: "Case Management"
description: |
Managing Cases
reasoning:
instructions: ->
| Run {!@actions.Fetch_Cases_by_Email} to get the Cases related to the Email.
| Run {!@actions.Update_Case} to update the case with the Comments shared.
actions:
Fetch_Cases_by_Email: @actions.Fetch_Cases_by_Email
with caseEmail = ...
Update_Case: @actions.Update_Case
with caseComment = ...
with caseId = ...
with casePriority = ...
actions:
Fetch_Cases_by_Email:
label: "Fetch Cases by Email"
description: |
Fetch Cases by Email
target: "flow://AF_Fetch_Cases_by_Email"
inputs:
caseEmail: string
label: "caseEmail"
description: "Stores the Case Email Address"
is_required: False
outputs:
listCases: list[object]
label: "listCases"
description: "Stores the Cases related to the Email Address"
complex_data_type_name: "lightning__recordInfoType"
is_displayable: False
filter_from_agent: False
message: string
label: "message"
description: "Stores the Success or Error Message"
is_displayable: False
filter_from_agent: False
success: boolean
label: "success"
description: "Stores whether the execution succeeded or not"
is_displayable: False
filter_from_agent: False
Update_Case:
label: "Update Case"
description: |
Update Case
target: "flow://AF_Update_Case"
inputs:
caseComment: string
label: "caseComment"
description: "Stores the Case Comments"
is_required: False
caseId: string
label: "caseId"
description: "Stores Case record ID"
is_required: False
casePriority: string
label: "Case Priority"
description: |
Case Priority. Allowed values (case-sensitive):
"Low", "Medium", "High".
Map the user's wording to the closest value.
Only use a value if the user said it, or said one of these exact synonyms:
- Low: "low", "low priority", "minor", "not urgent"
- Medium: "medium", "normal", "standard", "moderate"
- High: "high", "high priority", "urgent", "critical", "asap"
Do not infer or guess. If the user's wording is not in this list,
ask the user to choose one of the three allowed values.
Never pass any other value.
is_required: False
outputs:
caseRecord: object
label: "caseRecord"
description: "Stores the Case record"
complex_data_type_name: "lightning__recordInfoType"
is_displayable: False
filter_from_agent: False
message: string
label: "message"
description: "Stores the Success or Error Message for Case Update operation"
is_displayable: False
filter_from_agent: False
success: boolean
label: "success"
description: "Stores whether the Case update succeeded or not"
is_displayable: False
filter_from_agent: False
Technical Breakdown of the Parameter Instructions
The key section in the configuration above is the explicit prompt instruction inside the casePriorityparameter description:
- Explicit Value Whitelisting: Clearly state allowed values:
"Low","Medium","High". - Case Sensitivity Warning: Explicitly inform the model that matching is case-sensitive.
- Synonym Mapping Rules: Map natural language variants directly to allowed API values:
"critical"or"asap"$\rightarrow$"High""minor"or"not urgent"$\rightarrow$"Low"
- Negative Guardrails: Incorporate directives such as “Do not infer or guess” and “Never pass any other value”.
- Conversational Fallback: Instruct the agent to re-prompt the user to choose from valid options if no match is identified, rather than sending bad data down the pipeline.