platform-custom-metadata-type-generate
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseSalesforce Custom Metadata Type Generator and Validator
Salesforce Custom Metadata Type 生成器与验证器
When to Use This Skill
何时使用此技能
Use this skill when you need to:
- Create a Custom Metadata Type ()
__mdt - Generate or validate CMDT fields, including fields
MetadataRelationship - Generate CMDT records as deployable files
.md-meta.xml - Troubleshoot CMDT deployment errors
在以下场景中使用此技能:
- 创建自定义元数据类型()
__mdt - 生成或验证CMDT字段,包括字段
MetadataRelationship - 将CMDT记录生成为可部署的文件
.md-meta.xml - 排查CMDT部署错误
1. Overview and Purpose
1. 概述与用途
A Custom Metadata Type produces two separate artifact families, and most requests need both:
| Artifact | Path | Metadata type |
|---|---|---|
| Type definition | | |
| Fields | | |
| Records | | |
API name suffix: on the type; fields still end in .
__mdt__cThe defining advantage over a custom setting: CMDT records are metadata and therefore deploy between
orgs. When a user says configuration should "ship with the package" or "be the same in every org," CMDT
is the right answer.
The root element is, but almost none of a custom object's rules apply.<CustomObject>,sharingModel, andnameFieldare required or normal on a regular custom object and are hard errors here. Do not carry assumptions across fromdeploymentStatus.platform-custom-object-generate
自定义元数据类型会生成两类独立的工件,大多数需求会同时用到这两类:
| 工件 | 路径 | 元数据类型 |
|---|---|---|
| 类型定义 | | |
| 字段 | | |
| 记录 | | |
API名称后缀:类型后缀为;字段仍以结尾。
__mdt__c**相较于Custom Setting的核心优势:CMDT记录属于元数据,因此可在组织间部署。**当用户表示配置需要“随包发布”或“在所有组织中保持一致”时,CMDT是正确选择。
根元素为,但自定义对象的绝大多数规则并不适用。<CustomObject>、sharingModel和nameField在常规自定义对象中是必填或常规项,但在此处会导致严重错误。请勿照搬deploymentStatus的规则。platform-custom-object-generate
2. Syntactic Essentials — Type Definition (Tier 1)
2. 语法要点——类型定义(第一层)
Required and Allowed Elements
必填与允许的元素
| Element | Requirement | Notes |
|---|---|---|
| Required | Singular UI name |
| Required | Omitting it gives |
| Always include | |
| Always include | What this type configures and who owns it |
<pluralLabel>| 元素 | 要求 | 说明 |
|---|---|---|
| 必填 | 单数UI名称 |
| 必填 | 省略会报错: |
| 必须包含 | 取值为 |
| 必须包含 | 说明该类型的配置对象及负责人 |
<pluralLabel>Forbidden Elements
禁止的元素
Every element below produces — reusing a regular custom
object's skeleton (with , , a block, or ) is the
usual cause:
Cannot specify: <element> for Custom Metadata TypesharingModeldeploymentStatusnameFieldenableSearchsharingModelnameFielddeploymentStatusenableActivitiesenableReportsenableHistoryenableSearchCORRECT — minimum valid type:
__mdtxml
<?xml version="1.0" encoding="UTF-8"?>
<CustomObject xmlns="http://soap.sforce.com/2006/04/metadata">
<label>Partner Tier</label>
<pluralLabel>Partner Tiers</pluralLabel>
<description>Discount and threshold configuration per partner tier. Ships with the package; edited by the revenue ops team.</description>
<visibility>Public</visibility>
</CustomObject>以下元素都会触发错误——通常是因为复用了常规自定义对象的模板(包含、、块或):
Cannot specify: <element> for Custom Metadata TypesharingModeldeploymentStatusnameFieldenableSearchsharingModelnameFielddeploymentStatusenableActivitiesenableReportsenableHistoryenableSearch正确示例——最简有效类型:
__mdtxml
<?xml version="1.0" encoding="UTF-8"?>
<CustomObject xmlns="http://soap.sforce.com/2006/04/metadata">
<label>Partner Tier</label>
<pluralLabel>Partner Tiers</pluralLabel>
<description>Discount and threshold configuration per partner tier. Ships with the package; edited by the revenue ops team.</description>
<visibility>Public</visibility>
</CustomObject>3. Field Rules
3. 字段规则
This skill owns the CMDT-specific deltas only — the type allowlist, , and
below. For generic field mechanics ( derivation, ,
, , precision/scale, , ), follow
.
fieldManageabilityMetadataRelationship<fullName><label><description><inlineHelpText><length>visibleLinesplatform-custom-field-generate此技能仅负责CMDT特有的差异部分——即类型白名单、及下文的。通用字段机制(如推导、、、、精度/刻度、、)请遵循的规则。
fieldManageabilityMetadataRelationship<fullName><label><description><inlineHelpText><length>visibleLinesplatform-custom-field-generateSupported Field Types
支持的字段类型
CheckboxDateDateTimeEmailNumberPercentPhonePicklistTextTextAreaLongTextAreaUrlMetadataRelationshipCheckboxDateDateTimeEmailNumberPercentPhonePicklistTextTextAreaLongTextAreaUrlMetadataRelationshipUnsupported Field Types
不支持的字段类型
CurrencyAutoNumberMasterDetailSummaryLocationTimeEncryptedTextHtmlMultiselectPicklisttext
Type {TypeName} of CustomMetadataField {Object}__mdt.{Field}__c is not supported for the Entity {Object}__mdt(There is no trailing period.) Example:
Type Currency of CustomMetadataField Partner_Tier__mdt.Discount__c is not supported for the Entity Partner_Tier__mdtCurrency is the common trap — it works on a custom setting but not here. Use with
/ and put the currency in the label or help text.
Number<precision><scale>Formula fields are unsupported, but they break the pattern above. A element on an otherwise
legal type gives only:
<formula>text
Invalid data type.CurrencyAutoNumberMasterDetailSummaryLocationTimeEncryptedTextHtmlMultiselectPicklisttext
Type {TypeName} of CustomMetadataField {Object}__mdt.{Field}__c is not supported for the Entity {Object}__mdt(末尾无句号)示例:
Type Currency of CustomMetadataField Partner_Tier__mdt.Discount__c is not supported for the Entity Partner_Tier__mdtCurrency是常见陷阱——它在Custom Setting中可用,但在此处不可用。请使用并配置/,将货币信息放在标签或帮助文本中。
Number<precision><scale>公式字段不支持,但错误提示不符合上述模式。在合法类型中添加元素仅会报错:
<formula>text
Invalid data type.Lookup
is silently coerced — CRITICAL
LookupLookup
会被静默转换——关键注意事项
Lookup<type>Lookup</type>__mdtreferenceToMetadataRelationshipxml
<type>MetadataRelationship</type> <!-- was deployed as Lookup -->Always write explicitly. Emitting produces a green deploy and a
source-vs-org mismatch that churns in git the first time anyone retrieves. (Reproduced on a live deploy: a
resolvable returns as ; a non-resolvable is cleanly rejected.)
MetadataRelationshipLookupLookupMetadataRelationshipreferenceTo在字段中使用且指向真实sObject时不会报错:部署会成功,平台会将字段静默重写为。后续检索会显示用户从未编写过的字段:
__mdt<type>Lookup</type>referenceToMetadataRelationshipxml
<type>MetadataRelationship</type> <!-- 部署时为Lookup -->请始终显式使用。使用会导致部署成功,但会引发源码与组织的不一致,首次检索时会在Git中产生不必要的变更。(已在实际部署中验证:可解析的会被转换为;无法解析的会被明确拒绝。)
MetadataRelationshipLookupLookupMetadataRelationshipreferenceToMetadataRelationship
MetadataRelationshipMetadataRelationship
MetadataRelationshipThree targets, all valid. selects which.
referenceTo | Purpose | Extra requirement |
|---|---|---|
Another | Link two custom metadata types | Must be a different type |
| Point at an sObject | None |
| Point at a field | Requires |
xml
<?xml version="1.0" encoding="UTF-8"?>
<CustomField xmlns="http://soap.sforce.com/2006/04/metadata">
<fullName>Target_Field__c</fullName>
<label>Target Field</label>
<type>MetadataRelationship</type>
<referenceTo>FieldDefinition</referenceTo>
<metadataRelationshipControllingField>Partner_Tier__mdt.Target_Object__c</metadataRelationshipControllingField>
<relationshipLabel>Target Field</relationshipLabel>
<relationshipName>Target_Field</relationshipName>
</CustomField>The controlling field must be an relationship on the same type, referenced as
. Omitting it gives
EntityDefinitionType__mdt.Field__cMetadata relationships to Field Definition require a controlling field.Self-references are impossible. Pointing a at its own parent type fails with
(verbatim
from a live deploy) — use a second type.
MetadataRelationshipCannot add a self-lookup relationship child with cascade or restrict options to the object itself__mdt支持三种目标,由选择。
referenceTo | 用途 | 额外要求 |
|---|---|---|
另一个 | 关联两个自定义元数据类型 | 必须是不同的类型 |
| 指向sObject | 无 |
| 指向字段 | 必须包含 |
xml
<?xml version="1.0" encoding="UTF-8"?>
<CustomField xmlns="http://soap.sforce.com/2006/04/metadata">
<fullName>Target_Field__c</fullName>
<label>Target Field</label>
<type>MetadataRelationship</type>
<referenceTo>FieldDefinition</referenceTo>
<metadataRelationshipControllingField>Partner_Tier__mdt.Target_Object__c</metadataRelationshipControllingField>
<relationshipLabel>Target Field</relationshipLabel>
<relationshipName>Target_Field</relationshipName>
</CustomField>控制字段必须是同一类型上的关联,格式为。省略会报错:
EntityDefinitionType__mdt.Field__cMetadata relationships to Field Definition require a controlling field.不支持自引用。将指向自身父类型会报错:(直接取自实际部署)——请使用第二个类型。
MetadataRelationshipCannot add a self-lookup relationship child with cascade or restrict options to the object itself__mdt<fieldManageability>
<fieldManageability><fieldManageability>
<fieldManageability>Optional. It defaults to — do not add it unless the user wants a different value.
Valid values are , , and .
DeveloperControlledDeveloperControlledSubscriberControlledLockedIt is valid only on fields. On a regular custom object field or a custom setting field:
__mdttext
Field manageability cannot be set on this entity.可选,默认值为——除非用户需要其他值,否则不要添加。有效值为、和。
DeveloperControlledDeveloperControlledSubscriberControlledLocked此字段仅在字段上有效。在常规自定义对象字段或Custom Setting字段上使用会报错:
__mdttext
Field manageability cannot be set on this entity.4. CMDT Records (.md-meta.xml
)
.md-meta.xml4. CMDT记录(.md-meta.xml
)
.md-meta.xmlFilename convention
文件名约定
Write .
customMetadata/<TypeNameWithout__mdt>.<RecordDeveloperName>.md-meta.xmltext
customMetadata/Partner_Tier.Bronze_AMER.md-meta.xmlThe suffix in the filename also deploys and creates a real record, so it is tolerated — but
Salesforce's retrieve normalizes to the no-suffix form, so always write it without to avoid git
churn (detail in ).
__mdt__mdtreferences/cmdt-records.md格式为。
customMetadata/<TypeNameWithout__mdt>.<RecordDeveloperName>.md-meta.xmltext
customMetadata/Partner_Tier.Bronze_AMER.md-meta.xml文件名中包含后缀也可部署并创建真实记录,但Salesforce检索时会标准化为无后缀形式,因此请始终使用无后缀格式以避免Git变更(详情见)。
__mdtreferences/cmdt-records.mdRequired namespaces
必填命名空间
All three are mandatory on the root element — on values will not resolve without them.
xsi:typexml
<CustomMetadata xmlns="http://soap.sforce.com/2006/04/metadata"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">根元素必须包含全部三个命名空间——否则值的无法解析。
xsi:typexml
<CustomMetadata xmlns="http://soap.sforce.com/2006/04/metadata"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">xsi:type
mapping — every value needs one
xsi:typexsi:type
映射——每个值都需要指定
xsi:type| Field type | Correct | Example value |
|---|---|---|
| Checkbox | | |
| Date | | |
| DateTime | | |
| Number, Percent | | |
| Text, TextArea, LongTextArea | | |
| Email, Phone, Url | | |
| Picklist | | |
MetadataRelationship → | | |
MetadataRelationship → | | |
| any type, null | no |
A value pointing at another type via was not verified — expect
with the target's DeveloperName, but confirm.
__mdtMetadataRelationshipxsd:string| 字段类型 | 正确的 | 示例值 |
|---|---|---|
| Checkbox | | |
| Date | | |
| DateTime | | |
| Number, Percent | | |
| Text, TextArea, LongTextArea | | |
| Email, Phone, Url | | |
| Picklist | | |
MetadataRelationship → | | |
MetadataRelationship → | | |
| 任意类型,空值 | 无需 |
通过指向另一个类型的值未验证——预期使用目标的DeveloperName作为值,但需确认。
MetadataRelationship__mdtxsd:stringxsd:picklist
must not be emitted — CRITICAL
xsd:picklist禁止使用xsd:picklist
——关键注意事项
xsd:picklistSalesforce's own documentation tells you to use for Picklist fields. It is wrong — it is
not a valid XML Schema type. Instead of a clean validation error, the platform fails the entire deploy
server-side with no component-level diagnostics, taking every other component down with it. Always emit
for a Picklist field's value; never . See §2.
xsd:picklistxsd:stringxsd:picklistreferences/cmdt-records.mdSalesforce官方文档建议对Picklist字段使用,但这是错误的——它不是有效的XML Schema类型。平台不会给出清晰的验证错误,而是会在服务器端失败整个部署,且无组件级诊断信息,导致其他组件也部署失败。请始终为Picklist字段的值使用;绝不要使用。详情见第2节。
xsd:picklistxsd:stringxsd:picklistreferences/cmdt-records.mdRecord body rules
记录主体规则
- is required. Omitting it gives
<label>— note it reports the sObject field nameRequired fields are missing: [MasterLabel], notMasterLabel.label - is optional and defaults to
<protected>.false - Never put inside a
<fullName>block — it is a hard parse error.<values> - works on optional fields. On a required field it is rejected exactly as if the field were absent. Omitting
<value xsi:nil="true"/>on a non-nil value is always fatal, including for text fields.xsi:type
CORRECT — a complete record:
xml
<?xml version="1.0" encoding="UTF-8"?>
<CustomMetadata xmlns="http://soap.sforce.com/2006/04/metadata"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<label>Bronze AMER</label>
<protected>false</protected>
<values>
<field>Discount_Percent__c</field>
<value xsi:type="xsd:double">5.0</value>
</values>
<values>
<field>Region__c</field>
<value xsi:type="xsd:string">AMER</value>
</values>
<values>
<field>Effective_Date__c</field>
<value xsi:type="xsd:date">2024-01-15</value>
</values>
<values>
<field>Notes__c</field>
<value xsi:nil="true"/>
</values>
</CustomMetadata>- 是必填项。省略会报错:
<label>——注意错误提示中使用的是sObject字段名Required fields are missing: [MasterLabel],而非MasterLabel。label - 可选,默认值为
<protected>。false - 切勿在块中放入
<values>——这会导致解析错误。<fullName> - 适用于可选字段。在必填字段上使用会被拒绝,效果等同于未填写该字段。非空值省略
<value xsi:nil="true"/>始终会导致错误,包括文本字段。xsi:type
正确示例——完整记录:
xml
<?xml version="1.0" encoding="UTF-8"?>
<CustomMetadata xmlns="http://soap.sforce.com/2006/04/metadata"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<label>Bronze AMER</label>
<protected>false</protected>
<values>
<field>Discount_Percent__c</field>
<value xsi:type="xsd:double">5.0</value>
</values>
<values>
<field>Region__c</field>
<value xsi:type="xsd:string">AMER</value>
</values>
<values>
<field>Effective_Date__c</field>
<value xsi:type="xsd:date">2024-01-15</value>
</values>
<values>
<field>Notes__c</field>
<value xsi:nil="true"/>
</values>
</CustomMetadata>Record DeveloperName rules
记录DeveloperName规则
The name is the second segment of the filename. It must begin with a letter, contain only alphanumerics and
underscores, not end with an underscore, not contain two consecutive underscores, and be at most 40
characters. Violations give:
text
Custom Metadata Record Name: The <Type>__mdt API Name can only contain underscores and alphanumeric characters. It must be unique, begin with a letter, not include spaces, not end with an underscore, and not contain two consecutive underscores.Over 40 characters gives (no space after the colon).
Value too long for field: fullName maximum length is:40名称是文件名的第二部分。必须以字母开头,仅包含字母数字和下划线,不以结尾,不包含连续两个下划线,且长度最多40个字符。违反规则会报错:
text
Custom Metadata Record Name: The <Type>__mdt API Name can only contain underscores and alphanumeric characters. It must be unique, begin with a letter, not include spaces, not end with an underscore, and not contain two consecutive underscores.超过40个字符会报错:(冒号后无空格)。
Value too long for field: fullName maximum length is:40Deploy ordering
部署顺序
No ordering constraint — the type and every referenced field only need to resolve (already in the org,
or present in the same deploy). Two failures tell you what is missing:
(the type is missing) and
(the type exists but the field does not).
Custom metadata type <Type>__mdt is not available in this organization.<Type>__mdt: could not find fields: <Field>__c→ Full record-value error catalog and the coercion asymmetry: .
xsi:typereferences/cmdt-records.md无顺序约束——类型及所有引用字段只需能被解析(已存在于组织中,或在同一部署包中)。两种错误提示表明缺少相关内容:(类型缺失)和(类型存在但字段缺失)。
Custom metadata type <Type>__mdt is not available in this organization.<Type>__mdt: could not find fields: <Field>__c→ 完整的记录值错误目录及转换不对称性:。
xsi:typereferences/cmdt-records.mdGenerating records from user input
根据用户输入生成记录
Record data arrives three ways; in each case emit one per row, mapping
columns to / pairs with the right :
<Type>.<Record>.md-meta.xml<field><value>xsi:type- Inline list/table — map columns straight to fields.
- CSV — header = field API names (or map labels to them), each line = one record; take the DeveloperName from a key column.
- Prose — infer the rows ("Bronze at 5%, Gold at 15%") and confirm the field mapping before generating.
Derive every DeveloperName deterministically from the key column or label — never free-hand one. For each
row, run before writing its record file (same input →
same valid name; empty/all-symbol/non-Latin labels fall back to ).
scripts/sanitize-developer-name.sh "<LABEL>" <ROW>Record_<ROW>The transform is many-to-one — and both yield , and since
each record is , a collision silently overwrites a row. After deriving the
whole batch, check duplicates before writing; on any collision stop and report the colliding source
labels rather than overwrite (append a deterministic / suffix only if the user asks to auto-resolve).
Ordered algorithm, ASCII-only limitation, uniqueness check, and worked examples: §7.
United StatesUnited-StatesUnited_States<Type>.<DeveloperName>.md-meta.xml_2_3references/cmdt-records.md记录数据有三种来源,每种情况都需为每行生成一个文件,将列映射为/对,并使用正确的:
<Type>.<Record>.md-meta.xml<field><value>xsi:type- 内联列表/表格——直接将列映射到字段。
- CSV——表头=字段API名称(或标签映射到API名称),每行=一条记录;从关键列获取DeveloperName。
- ** prose描述**——推断行内容(如“Bronze折扣5%,Gold折扣15%”),生成前确认字段映射。
必须确定性地从关键列或标签推导每个DeveloperName——切勿随意编写。对于每行,在写入记录文件前运行(相同输入→相同有效名称;空标签/全符号/非拉丁标签默认使用)。
scripts/sanitize-developer-name.sh "<LABEL>" <ROW>Record_<ROW>转换是多对一的——和都会生成,由于每个记录对应文件,冲突会静默覆盖行内容。推导完所有记录后,写入前检查重复项;若有冲突,停止并报告冲突的源标签,而非覆盖(仅当用户要求自动解决时,才添加确定性的/后缀)。有序算法、ASCII限制、唯一性检查及示例:第7节。
United StatesUnited-StatesUnited_States<Type>.<DeveloperName>.md-meta.xml_2_3references/cmdt-records.mdConsuming records in Apex
在Apex中使用记录
Records are read through the generated typed class — no SOQL, no query rows consumed, safe in loops and
triggers:
apex
Map<String, Partner_Tier__mdt> all = Partner_Tier__mdt.getAll();
Partner_Tier__mdt bronze = Partner_Tier__mdt.getInstance('Bronze_AMER'); // by DeveloperNameAccessor truncation — CRITICAL for . / return only the first
255 characters of any field; longer values are silently truncated for those callers and
must be read via SOQL (). Say so whenever you put a on a
CMDT.
LongTextAreagetAll()getInstance()LongTextAreaSELECT ... FROM Partner_Tier__mdtLongTextArea通过生成的类型化类读取记录——无需SOQL,不消耗查询行数,可安全用于循环和触发器:
apex
Map<String, Partner_Tier__mdt> all = Partner_Tier__mdt.getAll();
Partner_Tier__mdt bronze = Partner_Tier__mdt.getInstance('Bronze_AMER'); // 通过DeveloperName获取访问器截断——关键注意事项。/仅返回任何字段的前255个字符;更长的值会被这些访问器静默截断,必须通过SOQL读取完整值()。当在CMDT中添加字段时,请告知用户此限制。
LongTextAreagetAll()getInstance()LongTextAreaSELECT ... FROM Partner_Tier__mdtLongTextArea5. Choosing the Right Component
5. 选择正确的组件
Before generating, confirm a CMDT is what the user needs.
| If the config is… | Use | Why |
|---|---|---|
| Reference data that must deploy between orgs with its records | CMDT (this skill) | Records are metadata |
| An admin-maintained mapping / lookup / crosswalk table (field↔field, code↔code, "map A to B") | CMDT (this skill) | Editable reference data, one record per pair |
| Admin-editable per profile/user, or org-local | | Values are data and stay in one org |
| Business records users create and edit at runtime | | CMDT records are not transactional data |
| Translatable UI text | Custom Label — not generated here | Labels are the translation surface |
| Credentials, API keys, tokens | Named Credential / External Credential — not generated here | See Section 6 |
| A permission check in Apex or a flow | Custom Permission — not generated here | Boolean access belongs in the permission model |
The distinction that matters most: CMDT records deploy, custom setting values do not. If the user needs
admins to edit values per profile at runtime, that is a custom setting, not a CMDT.
Field-mapping and lookup tables are a canonical CMDT use case. When a user asks to "map fields from A to B," maintain a code-to-code lookup, or keep a crosswalk admins can edit, model it as a CMDT — one record per pair (e.g./Lead_Field__c, orTarget_Field__cfields toMetadataRelationship) — never a hardcoded ApexFieldDefinition, constant, or Flow decision. Phrasing like "for conversion" or "for our integration" does not make it code: if admins maintain the pairs without a deploy, it is CMDT reference data.Map
生成前,请确认用户确实需要CMDT。
| 配置场景 | 使用组件 | 原因 |
|---|---|---|
| 需要在组织间部署的参考数据及对应记录 | CMDT(此技能) | 记录属于元数据 |
| 管理员维护的映射/查找/对照表(字段↔字段、代码↔代码、“将A映射到B”) | CMDT(此技能) | 可编辑的参考数据,每对对应一条记录 |
| 管理员可按配置文件/用户编辑,或仅在当前组织生效 | | 值属于数据,仅保留在单个组织中 |
| 用户在运行时创建和编辑的业务记录 | | CMDT记录不是事务性数据 |
| 可翻译的UI文本 | 自定义标签——不由本技能生成 | 标签是翻译载体 |
| 凭证、API密钥、令牌 | Named Credential / External Credential——不由本技能生成 | 见第6节 |
| Apex或Flow中的权限检查 | 自定义权限——不由本技能生成 | 布尔型权限属于权限模型 |
最关键的区别:CMDT记录可部署,Custom Setting值不可部署。如果用户需要管理员在运行时按配置文件编辑值,应使用Custom Setting而非CMDT。
字段映射和查找表是CMDT的典型使用场景。当用户要求“将字段从A映射到B”、维护代码到代码的查找表,或保留管理员可编辑的对照表时,请将其建模为CMDT——每对对应一条记录(如/Lead_Field__c,或指向Target_Field__c的FieldDefinition字段)——绝不要硬编码为ApexMetadataRelationship、常量或Flow决策。即使描述中包含“用于转换”或“用于集成”,只要管理员无需部署即可修改配对,就属于CMDT参考数据。Map
6. Visibility, Secrets, and the No-Silent-Downgrade Rule
6. 可见性、密钥与无静默降级规则
Protected
and PackageProtected
are org-type dependent
ProtectedPackageProtectedProtected
和PackageProtected
依赖组织类型
ProtectedPackageProtectedBoth deploy only in a developer, sandbox, or scratch org. Anywhere else:
text
You can't set the visibility for a Custom Metadata Type to Protected unless you are in a developer, sandbox, or scratch org.PackageProtectedPackageProtected两者仅能在开发环境、沙盒或临时组织中部署。在其他环境中会报错:
text
You can't set the visibility for a Custom Metadata Type to Protected unless you are in a developer, sandbox, or scratch org.PackageProtectedProtectedPackageProtectedThe no-silent-downgrade rule — CRITICAL
无静默降级规则——关键注意事项
If fails because of the org type, never "fix" it by switching to . Stop and tell the
user. A silent downgrade turns a deliberate confidentiality choice into a world-readable component with a
green deploy and no warning — the worst possible outcome, because nothing signals that anything changed.
ProtectedPublicReport the situation instead: the org does not permit , so the options are to deploy to a
dev/sandbox/scratch org or to accept . Let the user choose.
ProtectedPublicThis applies to any narrowing of visibility, not only this error.
如果因组织类型导致部署失败,绝不要通过切换为来“修复”。停止操作并告知用户。静默降级会将刻意设置的保密组件变为全局可读组件,且部署成功无警告——这是最糟糕的结果,因为没有任何信号表明发生了变更。
ProtectedPublic应告知用户当前情况:组织不允许使用,因此选项为部署到开发/沙盒/临时组织,或接受使用。让用户自行选择。
ProtectedPublic此规则适用于任何可见性限制场景,不仅限于此错误。
Secrets do not belong in a CMDT
密钥不应存储在CMDT中
A CMDT is not a secret store. restricts access from outside the namespace, but it is not
encryption and it does not protect the value from code or admins inside it.
ProtectedWhen a user asks to store an API key, password, token, client secret, or certificate in a CMDT:
- Warn prominently and first — before generating anything — that a CMDT is the wrong home for a
credential, and that is not encryption.
Protected - Recommend the right component — a Named Credential with an External Credential. Say plainly that this skill does not generate them.
- If the user still insists, comply — generate the CMDT with visibility where the org allows it, and keep the warning in the response. Do not silently refuse, and do not silently obey.
Protected
The two rules compose, and the order matters. If the user insists on a CMDT for a secret and the org
rejects , the no-silent-downgrade rule is what prevents the key from landing in a
component. Stop and report — never downgrade a secret-bearing type to .
ProtectedPublicPublicCMDT不是密钥存储。仅限制命名空间外的访问,但不提供加密,也无法保护命名空间内代码或管理员对值的访问。
Protected当用户要求在CMDT中存储API密钥、密码、令牌、客户端密钥或证书时:
- 首先明确警告——在生成任何内容前,告知用户CMDT不是存储凭证的合适选择,且不提供加密。
Protected - 推荐正确组件——使用带External Credential的Named Credential。明确说明此技能不会生成该组件。
- 如果用户仍坚持,再执行操作——在组织允许的情况下生成带可见性的CMDT,并在响应中保留警告。不要静默拒绝,也不要静默执行。
Protected
两条规则需结合使用,且顺序重要。如果用户坚持使用CMDT存储密钥,且组织拒绝,无静默降级规则可防止密钥被存储在组件中。停止操作并报告——绝不要将存储密钥的类型降级为。
ProtectedPublicPublic7. Deployment Error Reference
7. 部署错误参考
Every type- and field-level error string is stated inline in Sections 2–4, next to the mistake that causes
it (, the unsupported-type string,
for a formula, , the controlling-
field and self-lookup errors, and the case).
Cannot specify: <element> for Custom Metadata TypeInvalid data type.Field manageability cannot be set on this entity.MetadataRelationshipMust specify a non-empty plural labelThe full verbatim record-value catalog — every wrong- rejection, , nil-on-required, the DeveloperName rules, and the exact-text traps (field named by Label not
API name, the doubled space and typo in the no- error, with no
space) — is in .
xsi:typeRequired fields are missing: [MasterLabel]i.g.xsi:typemaximum length is:40references/cmdt-records.mdOne matching caution: the suffix here is (spaced, title case); custom settings
use . Do not assume a shared template when matching these strings.
for Custom Metadata Typefor CustomSettings所有类型和字段级错误信息已在第2-4节中与对应错误场景一同列出(如、不支持类型的错误信息、公式字段的、、控制字段和自引用错误,以及错误)。
Cannot specify: <element> for Custom Metadata TypeInvalid data type.Field manageability cannot be set on this entity.MetadataRelationshipMust specify a non-empty plural label完整的记录值错误目录——包括所有错误的拒绝提示、、必填字段空值、DeveloperName规则,以及文本陷阱(字段使用标签而非API名称、无错误中的空格和拼写错误、无空格)——见****。
xsi:typeRequired fields are missing: [MasterLabel]xsi:typei.g.maximum length is:40references/cmdt-records.md注意:此处错误后缀为(空格分隔、标题大小写);Custom Setting的错误后缀为。匹配错误信息时不要假设共用模板。
for Custom Metadata Typefor CustomSettings8. Verification Checklist
8. 验证检查清单
Type Definition Checks
类型定义检查
- Are ,
<label>, and<pluralLabel>all present?<visibility> - Is present and specific?
<description> - Are ,
<sharingModel>, and<nameField>ABSENT?<deploymentStatus> - Are ,
<enableActivities>,<enableReports>, and<enableHistory>ABSENT?<enableSearch> - Does the directory and filename end in ?
__mdt
- 是否包含、
<label>和<pluralLabel>?<visibility> - 是否包含且内容明确?
<description> - 是否未包含、
<sharingModel>和<nameField>?<deploymentStatus> - 是否未包含、
<enableActivities>、<enableReports>和<enableHistory>?<enableSearch> - 目录和文件名是否以结尾?
__mdt
Field Checks
字段检查
- Is every field type in the supported list (Section 3)?
- Is absent? (unsupported here — use
Currency)Number - Is every element absent?
<formula> - Is absent, written as
<type>Lookup</type>instead? CRITICAL —MetadataRelationshipdeploys silently and is rewrittenLookup - For relationships, is
FieldDefinitionpresent?<metadataRelationshipControllingField> - Does no point at its own parent type?
MetadataRelationship - Is omitted unless a non-default value was requested?
<fieldManageability>
- 所有字段类型是否在第3节的支持列表中?
- 是否未包含?(此处不支持——请使用
Currency)Number - 是否未包含任何元素?
<formula> - 是否未包含,而是使用
<type>Lookup</type>?关键注意事项——MetadataRelationship会静默部署并被重写Lookup - 对于关联,是否包含
FieldDefinition?<metadataRelationshipControllingField> - 是否没有指向自身父类型?
MetadataRelationship - 是否仅在用户要求非默认值时才添加?
<fieldManageability>
Record Checks CRITICAL
记录检查(关键)
- Is the filename without
<Type>.<Record>.md-meta.xml?__mdt - Are all three namespaces (,
xmlns,xmlns:xsd) on the root element?xmlns:xsi - Does every non-nil carry an
<value>?xsi:type - Is absent everywhere? (crashes the whole deploy — use
xsi:type="xsd:picklist")xsd:string - Does each match the field type per the Section 4 table?
xsi:type - Is present on every record?
<label> - Is absent from every
<fullName>block?<values> - Is every required field given a real value rather than ?
xsi:nil="true" - Is every record DeveloperName ≤ 40 characters, starting with a letter, no spaces or hyphens?
- If records came from a batch/list/CSV, are all derived DeveloperNames distinct (checked with ), with any collision reported rather than silently overwriting a row? CRITICAL — a collision loses a record with no deploy error
sort | uniq -d - Does every name a field that exists on the type or is in this deploy?
<field> - If records came from a list, CSV, or prose description, is there exactly one file per row with the columns mapped to the right fields?
- 文件名是否为且不包含
<Type>.<Record>.md-meta.xml?__mdt - 根元素是否包含全部三个命名空间(、
xmlns、xmlns:xsd)?xmlns:xsi - 所有非空是否都包含
<value>?xsi:type - 是否未包含?(会导致整个部署失败——请使用
xsi:type="xsd:picklist")xsd:string - 每个是否与第4节表格中的字段类型匹配?
xsi:type - 每条记录是否包含?
<label> - 所有块中是否未包含
<values>?<fullName> - 所有必填字段是否都设置了真实值而非?
xsi:nil="true" - 每条记录的DeveloperName是否≤40字符、以字母开头、无空格或连字符?
- 如果记录来自批量列表/CSV,所有推导的DeveloperName是否唯一(使用检查),且冲突已报告而非静默覆盖?关键注意事项——冲突会导致记录丢失且无部署错误
sort | uniq -d - 每个是否指向该类型已存在或在本次部署中的字段?
<field> - 如果记录来自列表、CSV或 prose描述,是否每行对应一个文件且列映射到正确字段?
Consumption Checks
使用检查
- If the user asked how to read the records, was an Apex snippet given using /
getAll()?getInstance(developerName) - If any record populates a , was the user warned the accessors truncate to 255 characters and that SOQL is needed for the full value?
LongTextArea
- 如果用户询问如何读取记录,是否提供了使用/
getAll()的Apex代码片段?getInstance(developerName) - 如果任何记录填充了字段,是否告知用户访问器会截断为255字符,需使用SOQL读取完整值?
LongTextArea
Security Checks CRITICAL
安全检查(关键)
- If the request involves a secret, key, token, or password, was the warning given before generating, with a Named Credential recommended?
- Was left intact rather than silently downgraded to
Protectedon an org-type failure?Public
- 如果请求涉及密钥、令牌或密码,是否在生成前给出警告,并推荐使用Named Credential?
- 在组织类型不支持的情况下,是否保留而非静默降级为
Protected?Public
Component-Choice Checks
组件选择检查
- If admins need to edit values per profile or user at runtime, was recommended instead?
platform-custom-setting-generate - If the data is really transactional business records, was recommended instead?
platform-custom-object-generate
- 如果管理员需要在运行时按配置文件/用户编辑值,是否推荐使用?
platform-custom-setting-generate - 如果数据是事务性业务记录,是否推荐使用?
platform-custom-object-generate
Reference File Index
参考文件索引
| File | When to read |
|---|---|
| Debugging a CMDT record deploy — full verbatim record-value error catalog, the type-coercion asymmetry (which |
| 文件 | 阅读场景 |
|---|---|
| 排查CMDT记录部署问题——完整的记录值错误目录、平台静默接受的 |