platform-custom-metadata-type-generate

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Salesforce 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
    MetadataRelationship
    fields
  • Generate CMDT records as deployable
    .md-meta.xml
    files
  • 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:
ArtifactPathMetadata type
Type definition
objects/<Name>__mdt/<Name>__mdt.object-meta.xml
CustomObject
Fields
objects/<Name>__mdt/fields/<Field>__c.field-meta.xml
CustomField
Records
customMetadata/<Name>.<Record>.md-meta.xml
CustomMetadata
API name suffix:
__mdt
on the type; fields still end in
__c
.
The 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
<CustomObject>
, but almost none of a custom object's rules apply.
sharingModel
,
nameField
, and
deploymentStatus
are required or normal on a regular custom object and are hard errors here. Do not carry assumptions across from
platform-custom-object-generate
.

自定义元数据类型会生成两类独立的工件,大多数需求会同时用到这两类:
工件路径元数据类型
类型定义
objects/<Name>__mdt/<Name>__mdt.object-meta.xml
CustomObject
字段
objects/<Name>__mdt/fields/<Field>__c.field-meta.xml
CustomField
记录
customMetadata/<Name>.<Record>.md-meta.xml
CustomMetadata
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

必填与允许的元素

ElementRequirementNotes
<label>
RequiredSingular UI name
<pluralLabel>
RequiredOmitting it gives
Must specify a non-empty plural label for the CustomObject
<visibility>
Always include
Public
, or
Protected
/
PackageProtected
only in dev/sandbox/scratch (Section 6)
<description>
Always includeWhat this type configures and who owns it
<pluralLabel>
being required here but forbidden on a custom setting is the most commonly inverted rule between the two families. Neither failure mentions the other family's rule.
元素要求说明
<label>
必填单数UI名称
<pluralLabel>
必填省略会报错:
Must specify a non-empty plural label for the CustomObject
<visibility>
必须包含取值为
Public
;仅在开发环境/沙盒/临时组织中可使用
Protected
/
PackageProtected
(见第6节)
<description>
必须包含说明该类型的配置对象及负责人
<pluralLabel>
在此处必填但在Custom Setting中禁止使用,这是两者最常被混淆的规则。两类组件的错误提示都不会提及对方的规则。

Forbidden Elements

禁止的元素

Every element below produces
Cannot specify: <element> for Custom Metadata Type
— reusing a regular custom object's skeleton (with
sharingModel
,
deploymentStatus
, a
nameField
block, or
enableSearch
) is the usual cause:
sharingModel
,
nameField
,
deploymentStatus
,
enableActivities
,
enableReports
,
enableHistory
,
enableSearch
CORRECT — minimum valid
__mdt
type:
xml
<?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 Type
——通常是因为复用了常规自定义对象的模板(包含
sharingModel
deploymentStatus
nameField
块或
enableSearch
):
sharingModel
nameField
deploymentStatus
enableActivities
enableReports
enableHistory
enableSearch
正确示例——最简有效
__mdt
类型:
xml
<?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,
fieldManageability
, and
MetadataRelationship
below. For generic field mechanics (
<fullName>
derivation,
<label>
,
<description>
,
<inlineHelpText>
, precision/scale,
<length>
,
visibleLines
), follow
platform-custom-field-generate
.
此技能仅负责CMDT特有的差异部分——即类型白名单、
fieldManageability
及下文的
MetadataRelationship
。通用字段机制(如
<fullName>
推导、
<label>
<description>
<inlineHelpText>
、精度/刻度、
<length>
visibleLines
)请遵循
platform-custom-field-generate
的规则。

Supported Field Types

支持的字段类型

Checkbox
,
Date
,
DateTime
,
Email
,
Number
,
Percent
,
Phone
,
Picklist
,
Text
,
TextArea
,
LongTextArea
,
Url
, plus
MetadataRelationship
.
Checkbox
Date
DateTime
Email
Number
Percent
Phone
Picklist
Text
TextArea
LongTextArea
Url
,以及
MetadataRelationship

Unsupported Field Types

不支持的字段类型

Currency
,
AutoNumber
,
MasterDetail
,
Summary
,
Location
,
Time
,
EncryptedText
,
Html
,
MultiselectPicklist
. Each fails with a precise, well-formed error:
text
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__mdt
Currency is the common trap — it works on a custom setting but not here. Use
Number
with
<precision>
/
<scale>
and put the currency in the label or help text.
Formula fields are unsupported, but they break the pattern above. A
<formula>
element on an otherwise legal type gives only:
text
Invalid data type.
Currency
AutoNumber
MasterDetail
Summary
Location
Time
EncryptedText
Html
MultiselectPicklist
。每种类型都会触发明确的错误:
text
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__mdt
Currency是常见陷阱——它在Custom Setting中可用,但在此处不可用。请使用
Number
并配置
<precision>
/
<scale>
,将货币信息放在标签或帮助文本中。
公式字段不支持,但错误提示不符合上述模式。在合法类型中添加
<formula>
元素仅会报错:
text
Invalid data type.

Lookup
is silently coerced — CRITICAL

Lookup
会被静默转换——关键注意事项

<type>Lookup</type>
on a
__mdt
does not fail when its
referenceTo
resolves to a real sObject: the deploy is green and the platform silently rewrites the field to
MetadataRelationship
. A later retrieve shows a field the user never wrote:
xml
<type>MetadataRelationship</type>   <!-- was deployed as Lookup -->
Always write
MetadataRelationship
explicitly.
Emitting
Lookup
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
Lookup
returns as
MetadataRelationship
; a non-resolvable
referenceTo
is cleanly rejected.)
__mdt
字段中使用
<type>Lookup</type>
referenceTo
指向真实sObject时不会报错:部署会成功,平台会将字段静默重写为
MetadataRelationship
。后续检索会显示用户从未编写过的字段:
xml
<type>MetadataRelationship</type>   <!-- 部署时为Lookup -->
请始终显式使用
MetadataRelationship
。使用
Lookup
会导致部署成功,但会引发源码与组织的不一致,首次检索时会在Git中产生不必要的变更。(已在实际部署中验证:可解析的
Lookup
会被转换为
MetadataRelationship
;无法解析的
referenceTo
会被明确拒绝。)

MetadataRelationship

MetadataRelationship

Three targets, all valid.
referenceTo
selects which.
<referenceTo>
PurposeExtra requirement
Another
__mdt
type
Link two custom metadata typesMust be a different type
EntityDefinition
Point at an sObjectNone
FieldDefinition
Point at a fieldRequires
<metadataRelationshipControllingField>
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
EntityDefinition
relationship on the same type, referenced as
Type__mdt.Field__c
. Omitting it gives
Metadata relationships to Field Definition require a controlling field.
Self-references are impossible. Pointing a
MetadataRelationship
at its own parent type fails with
Cannot add a self-lookup relationship child with cascade or restrict options to the object itself
(verbatim from a live
__mdt
deploy) — use a second type.
支持三种目标,由
referenceTo
选择。
<referenceTo>
用途额外要求
另一个
__mdt
类型
关联两个自定义元数据类型必须是不同的类型
EntityDefinition
指向sObject
FieldDefinition
指向字段必须包含
<metadataRelationshipControllingField>
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>
控制字段必须是同一类型上的
EntityDefinition
关联,格式为
Type__mdt.Field__c
。省略会报错:
Metadata relationships to Field Definition require a controlling field.
不支持自引用。将
MetadataRelationship
指向自身父类型会报错:
Cannot add a self-lookup relationship child with cascade or restrict options to the object itself
(直接取自实际
__mdt
部署)——请使用第二个类型。

<fieldManageability>

<fieldManageability>

Optional. It defaults to
DeveloperControlled
— do not add it unless the user wants a different value. Valid values are
DeveloperControlled
,
SubscriberControlled
, and
Locked
.
It is valid only on
__mdt
fields. On a regular custom object field or a custom setting field:
text
Field manageability cannot be set on this entity.

可选,默认值为
DeveloperControlled
——除非用户需要其他值,否则不要添加。有效值为
DeveloperControlled
SubscriberControlled
Locked
此字段仅在
__mdt
字段上有效。在常规自定义对象字段或Custom Setting字段上使用会报错:
text
Field manageability cannot be set on this entity.

4. CMDT Records (
.md-meta.xml
)

4. CMDT记录(
.md-meta.xml

Filename convention

文件名约定

Write
customMetadata/<TypeNameWithout__mdt>.<RecordDeveloperName>.md-meta.xml
.
text
customMetadata/Partner_Tier.Bronze_AMER.md-meta.xml
The
__mdt
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
__mdt
to avoid git churn (detail in
references/cmdt-records.md
).
格式为
customMetadata/<TypeNameWithout__mdt>.<RecordDeveloperName>.md-meta.xml
text
customMetadata/Partner_Tier.Bronze_AMER.md-meta.xml
文件名中包含
__mdt
后缀也可部署并创建真实记录,但Salesforce检索时会标准化为无后缀形式,因此请始终使用无后缀格式以避免Git变更(详情见
references/cmdt-records.md
)。

Required namespaces

必填命名空间

All three are mandatory on the root element —
xsi:type
on values will not resolve without them.
xml
<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
无法解析。
xml
<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:type
映射——每个值都需要指定

Field typeCorrect
xsi:type
Example value
Checkbox
xsd:boolean
true
Date
xsd:date
2024-01-15
DateTime
xsd:dateTime
2024-01-15T10:30:00.000Z
Number, Percent
xsd:double
42.0
Text, TextArea, LongTextArea
xsd:string
some text
Email, Phone, Url
xsd:string
a@b.com
Picklist
xsd:string
Beta
MetadataRelationship →
EntityDefinition
xsd:string
Account
MetadataRelationship →
FieldDefinition
xsd:string
Account.Name
any type, nullno
xsi:type
— write
<value xsi:nil="true"/>
A value pointing at another
__mdt
type
via
MetadataRelationship
was not verified — expect
xsd:string
with the target's DeveloperName, but confirm.
字段类型正确的
xsi:type
示例值
Checkbox
xsd:boolean
true
Date
xsd:date
2024-01-15
DateTime
xsd:dateTime
2024-01-15T10:30:00.000Z
Number, Percent
xsd:double
42.0
Text, TextArea, LongTextArea
xsd:string
some text
Email, Phone, Url
xsd:string
a@b.com
Picklist
xsd:string
Beta
MetadataRelationship →
EntityDefinition
xsd:string
Account
MetadataRelationship →
FieldDefinition
xsd:string
Account.Name
任意类型,空值无需
xsi:type
—— 写入
<value xsi:nil="true"/>
通过
MetadataRelationship
指向另一个
__mdt
类型
的值未验证——预期使用目标的DeveloperName作为
xsd:string
值,但需确认。

xsd:picklist
must not be emitted — CRITICAL

禁止使用
xsd:picklist
——关键注意事项

Salesforce's own documentation tells you to use
xsd:picklist
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
xsd:string
for a Picklist field's value; never
xsd:picklist
.
See
references/cmdt-records.md
§2.
Salesforce官方文档建议对Picklist字段使用
xsd:picklist
,但这是错误的
——它不是有效的XML Schema类型。平台不会给出清晰的验证错误,而是会在服务器端失败整个部署,且无组件级诊断信息,导致其他组件也部署失败。请始终为Picklist字段的值使用
xsd:string
;绝不要使用
xsd:picklist
。详情见
references/cmdt-records.md
第2节。

Record body rules

记录主体规则

  • <label>
    is required. Omitting it gives
    Required fields are missing: [MasterLabel]
    — note it reports the sObject field name
    MasterLabel
    , not
    label
    .
  • <protected>
    is optional and defaults to
    false
    .
  • Never put
    <fullName>
    inside a
    <values>
    block — it is a hard parse error.
  • <value xsi:nil="true"/>
    works on optional fields. On a required field it is rejected exactly as if the field were absent. Omitting
    xsi:type
    on a non-nil value is always fatal, including for text fields.
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>
    必填项。省略会报错:
    Required fields are missing: [MasterLabel]
    ——注意错误提示中使用的是sObject字段名
    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
Value too long for field: fullName maximum length is:40
(no space after the colon).
名称是文件名的第二部分。必须以字母开头,仅包含字母数字和下划线,不以结尾,不包含连续两个下划线,且长度最多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:40
(冒号后无空格)。

Deploy 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:
Custom metadata type <Type>__mdt is not available in this organization.
(the type is missing) and
<Type>__mdt: could not find fields: <Field>__c
(the type exists but the field does not).
→ Full record-value error catalog and the
xsi:type
coercion asymmetry:
references/cmdt-records.md
.
无顺序约束——类型及所有引用字段只需能被解析(已存在于组织中,或在同一部署包中)。两种错误提示表明缺少相关内容:
Custom metadata type <Type>__mdt is not available in this organization.
(类型缺失)和
<Type>__mdt: could not find fields: <Field>__c
(类型存在但字段缺失)。
→ 完整的记录值错误目录及
xsi:type
转换不对称性:
references/cmdt-records.md

Generating records from user input

根据用户输入生成记录

Record data arrives three ways; in each case emit one
<Type>.<Record>.md-meta.xml
per row
, mapping columns to
<field>
/
<value>
pairs with the right
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
scripts/sanitize-developer-name.sh "<LABEL>" <ROW>
before writing its record file (same input → same valid name; empty/all-symbol/non-Latin labels fall back to
Record_<ROW>
).
The transform is many-to-one
United States
and
United-States
both yield
United_States
, and since each record is
<Type>.<DeveloperName>.md-meta.xml
, 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
_2
/
_3
suffix only if the user asks to auto-resolve). Ordered algorithm, ASCII-only limitation, uniqueness check, and worked examples:
references/cmdt-records.md
§7
.
记录数据有三种来源,每种情况都需为每行生成一个
<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>
)。
转换是多对一的——
United States
United-States
都会生成
United_States
,由于每个记录对应
<Type>.<DeveloperName>.md-meta.xml
文件,冲突会静默覆盖行内容。推导完所有记录后,写入前检查重复项;若有冲突,停止并报告冲突的源标签,而非覆盖(仅当用户要求自动解决时,才添加确定性的
_2
/
_3
后缀)。有序算法、ASCII限制、唯一性检查及示例:
references/cmdt-records.md
第7节

Consuming 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 DeveloperName
Accessor truncation — CRITICAL for
LongTextArea
.
getAll()
/
getInstance()
return only the first 255 characters of any field; longer
LongTextArea
values are silently truncated for those callers and must be read via SOQL (
SELECT ... FROM Partner_Tier__mdt
). Say so whenever you put a
LongTextArea
on a CMDT.

通过生成的类型化类读取记录——无需SOQL,不消耗查询行数,可安全用于循环和触发器:
apex
Map<String, Partner_Tier__mdt> all = Partner_Tier__mdt.getAll();
Partner_Tier__mdt bronze = Partner_Tier__mdt.getInstance('Bronze_AMER');  // 通过DeveloperName获取
访问器截断——
LongTextArea
关键注意事项
getAll()
/
getInstance()
仅返回任何字段的前255个字符;更长的
LongTextArea
值会被这些访问器静默截断,必须通过SOQL读取完整值(
SELECT ... FROM Partner_Tier__mdt
)。当在CMDT中添加
LongTextArea
字段时,请告知用户此限制。

5. Choosing the Right Component

5. 选择正确的组件

Before generating, confirm a CMDT is what the user needs.
If the config is…UseWhy
Reference data that must deploy between orgs with its recordsCMDT (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
platform-custom-setting-generate
Values are data and stay in one org
Business records users create and edit at runtime
platform-custom-object-generate
CMDT records are not transactional data
Translatable UI textCustom Label — not generated hereLabels are the translation surface
Credentials, API keys, tokensNamed Credential / External Credential — not generated hereSee Section 6
A permission check in Apex or a flowCustom Permission — not generated hereBoolean 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
/
Target_Field__c
, or
MetadataRelationship
fields to
FieldDefinition
) — never a hardcoded Apex
Map
, 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.

生成前,请确认用户确实需要CMDT。
配置场景使用组件原因
需要在组织间部署的参考数据及对应记录CMDT(此技能)记录属于元数据
管理员维护的映射/查找/对照表(字段↔字段、代码↔代码、“将A映射到B”)CMDT(此技能)可编辑的参考数据,每对对应一条记录
管理员可按配置文件/用户编辑,或仅在当前组织生效
platform-custom-setting-generate
值属于数据,仅保留在单个组织中
用户在运行时创建和编辑的业务记录
platform-custom-object-generate
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
MetadataRelationship
字段)——绝不要硬编码为Apex
Map
、常量或Flow决策。即使描述中包含“用于转换”或“用于集成”,只要管理员无需部署即可修改配对,就属于CMDT参考数据。

6. Visibility, Secrets, and the No-Silent-Downgrade Rule

6. 可见性、密钥与无静默降级规则

Protected
and
PackageProtected
are org-type dependent

Protected
PackageProtected
依赖组织类型

Both 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.
PackageProtected
gives the same string with
PackageProtected
substituted. The failure is confirmed in a production-like org; that these values succeed in a dev, sandbox, or scratch org is taken from the message text rather than separately tested.
两者仅能在开发环境、沙盒或临时组织中部署。在其他环境中会报错:
text
You can't set the visibility for a Custom Metadata Type to Protected unless you are in a developer, sandbox, or scratch org.
PackageProtected
的错误提示类似,仅将
Protected
替换为
PackageProtected
。此错误已在类生产环境中确认;这些值可在开发/沙盒/临时组织中成功部署的结论来自错误提示文本,而非单独测试。

The no-silent-downgrade rule — CRITICAL

无静默降级规则——关键注意事项

If
Protected
fails because of the org type, never "fix" it by switching to
Public
.
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.
Report the situation instead: the org does not permit
Protected
, so the options are to deploy to a dev/sandbox/scratch org or to accept
Public
. Let the user choose.
This applies to any narrowing of visibility, not only this error.
如果因组织类型导致
Protected
部署失败,绝不要通过切换为
Public
来“修复”
。停止操作并告知用户。静默降级会将刻意设置的保密组件变为全局可读组件,且部署成功无警告——这是最糟糕的结果,因为没有任何信号表明发生了变更。
应告知用户当前情况:组织不允许使用
Protected
,因此选项为部署到开发/沙盒/临时组织,或接受使用
Public
。让用户自行选择。
此规则适用于任何可见性限制场景,不仅限于此错误。

Secrets do not belong in a CMDT

密钥不应存储在CMDT中

A CMDT is not a secret store.
Protected
restricts access from outside the namespace, but it is not encryption and it does not protect the value from code or admins inside it.
When a user asks to store an API key, password, token, client secret, or certificate in a CMDT:
  1. Warn prominently and first — before generating anything — that a CMDT is the wrong home for a credential, and that
    Protected
    is not encryption.
  2. Recommend the right component — a Named Credential with an External Credential. Say plainly that this skill does not generate them.
  3. If the user still insists, comply — generate the CMDT with
    Protected
    visibility where the org allows it, and keep the warning in the response. Do not silently refuse, and do not silently obey.
The two rules compose, and the order matters. If the user insists on a CMDT for a secret and the org rejects
Protected
, the no-silent-downgrade rule is what prevents the key from landing in a
Public
component. Stop and report — never downgrade a secret-bearing type to
Public
.

CMDT不是密钥存储。
Protected
仅限制命名空间外的访问,但不提供加密,也无法保护命名空间内代码或管理员对值的访问。
当用户要求在CMDT中存储API密钥、密码、令牌、客户端密钥或证书时:
  1. 首先明确警告——在生成任何内容前,告知用户CMDT不是存储凭证的合适选择,且
    Protected
    不提供加密。
  2. 推荐正确组件——使用带External CredentialNamed Credential。明确说明此技能不会生成该组件。
  3. 如果用户仍坚持,再执行操作——在组织允许的情况下生成带
    Protected
    可见性的CMDT,并在响应中保留警告。不要静默拒绝,也不要静默执行。
两条规则需结合使用,且顺序重要。如果用户坚持使用CMDT存储密钥,且组织拒绝
Protected
,无静默降级规则可防止密钥被存储在
Public
组件中。停止操作并报告——绝不要将存储密钥的类型降级为
Public

7. 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 (
Cannot specify: <element> for Custom Metadata Type
, the unsupported-type string,
Invalid data type.
for a formula,
Field manageability cannot be set on this entity.
, the
MetadataRelationship
controlling- field and self-lookup errors, and the
Must specify a non-empty plural label
case).
The full verbatim record-value catalog — every wrong-
xsi:type
rejection,
Required fields are missing: [MasterLabel]
, nil-on-required, the DeveloperName rules, and the exact-text traps (field named by Label not API name, the doubled space and
i.g.
typo in the no-
xsi:type
error,
maximum length is:40
with no space) — is in
references/cmdt-records.md
.
One matching caution: the suffix here is
for Custom Metadata Type
(spaced, title case); custom settings use
for CustomSettings
. Do not assume a shared template when matching these strings.

所有类型和字段级错误信息已在第2-4节中与对应错误场景一同列出(如
Cannot specify: <element> for Custom Metadata Type
、不支持类型的错误信息、公式字段的
Invalid data type.
Field manageability cannot be set on this entity.
MetadataRelationship
控制字段和自引用错误,以及
Must specify a non-empty plural label
错误)。
完整的记录值错误目录——包括所有错误
xsi:type
的拒绝提示、
Required fields are missing: [MasterLabel]
、必填字段空值、DeveloperName规则,以及文本陷阱(字段使用标签而非API名称、无
xsi:type
错误中的空格和
i.g.
拼写错误、
maximum length is:40
无空格)——见**
references/cmdt-records.md
**。
注意:此处错误后缀为
for Custom Metadata Type
(空格分隔、标题大小写);Custom Setting的错误后缀为
for CustomSettings
。匹配错误信息时不要假设共用模板。

8. Verification Checklist

8. 验证检查清单

Type Definition Checks

类型定义检查

  • Are
    <label>
    ,
    <pluralLabel>
    , and
    <visibility>
    all present?
  • Is
    <description>
    present and specific?
  • Are
    <sharingModel>
    ,
    <nameField>
    , and
    <deploymentStatus>
    ABSENT?
  • Are
    <enableActivities>
    ,
    <enableReports>
    ,
    <enableHistory>
    , and
    <enableSearch>
    ABSENT?
  • 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
    Currency
    absent? (unsupported here — use
    Number
    )
  • Is every
    <formula>
    element absent?
  • Is
    <type>Lookup</type>
    absent, written as
    MetadataRelationship
    instead? CRITICAL —
    Lookup
    deploys silently and is rewritten
  • For
    FieldDefinition
    relationships, is
    <metadataRelationshipControllingField>
    present?
  • Does no
    MetadataRelationship
    point at its own parent type?
  • Is
    <fieldManageability>
    omitted unless a non-default value was requested?
  • 所有字段类型是否在第3节的支持列表中?
  • 是否未包含
    Currency
    ?(此处不支持——请使用
    Number
  • 是否未包含任何
    <formula>
    元素?
  • 是否未包含
    <type>Lookup</type>
    ,而是使用
    MetadataRelationship
    ?关键注意事项——
    Lookup
    会静默部署并被重写
  • 对于
    FieldDefinition
    关联,是否包含
    <metadataRelationshipControllingField>
  • 是否没有
    MetadataRelationship
    指向自身父类型?
  • 是否仅在用户要求非默认值时才添加
    <fieldManageability>

Record Checks CRITICAL

记录检查(关键)

  • Is the filename
    <Type>.<Record>.md-meta.xml
    without
    __mdt
    ?
  • Are all three namespaces (
    xmlns
    ,
    xmlns:xsd
    ,
    xmlns:xsi
    ) on the root element?
  • Does every non-nil
    <value>
    carry an
    xsi:type
    ?
  • Is
    xsi:type="xsd:picklist"
    absent everywhere? (crashes the whole deploy — use
    xsd:string
    )
  • Does each
    xsi:type
    match the field type per the Section 4 table?
  • Is
    <label>
    present on every record?
  • Is
    <fullName>
    absent from every
    <values>
    block?
  • 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
    sort | uniq -d
    ), with any collision reported rather than silently overwriting a row? CRITICAL — a collision loses a record with no deploy error
  • Does every
    <field>
    name a field that exists on the type or is in this deploy?
  • 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
  • 每个
    xsi:type
    是否与第4节表格中的字段类型匹配?
  • 每条记录是否包含
    <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
    LongTextArea
    , was the user warned the accessors truncate to 255 characters and that SOQL is needed for the full value?
  • 如果用户询问如何读取记录,是否提供了使用
    getAll()
    /
    getInstance(developerName)
    的Apex代码片段?
  • 如果任何记录填充了
    LongTextArea
    字段,是否告知用户访问器会截断为255字符,需使用SOQL读取完整值?

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
    Protected
    left intact rather than silently downgraded to
    Public
    on an org-type failure?
  • 如果请求涉及密钥、令牌或密码,是否在生成前给出警告,并推荐使用Named Credential?
  • 在组织类型不支持的情况下,是否保留
    Protected
    而非静默降级为
    Public

Component-Choice Checks

组件选择检查

  • If admins need to edit values per profile or user at runtime, was
    platform-custom-setting-generate
    recommended instead?
  • If the data is really transactional business records, was
    platform-custom-object-generate
    recommended instead?

  • 如果管理员需要在运行时按配置文件/用户编辑值,是否推荐使用
    platform-custom-setting-generate
  • 如果数据是事务性业务记录,是否推荐使用
    platform-custom-object-generate

Reference File Index

参考文件索引

FileWhen to read
references/cmdt-records.md
Debugging a CMDT record deploy — full verbatim record-value error catalog, the type-coercion asymmetry (which
xsi:type
mismatches the platform silently accepts), and worked record examples
文件阅读场景
references/cmdt-records.md
排查CMDT记录部署问题——完整的记录值错误目录、平台静默接受的
xsi:type
不匹配情况,以及记录示例