A guide for adding new diagnostic error codes to the Minecraft Bedrock Language Server.
- Choose error code location based on type (behavior pack, resource pack, general, minecraft-specific)
- Follow naming convention:
category.subcategory.type.detail - Use
diagnoser.add()with position, message, severity, and code - Test your diagnostic
The diagnostic system provides error checking and validation for Minecraft Bedrock projects. It helps developers identify issues in behavior packs, resource packs, and other project files.
Package: packages/bedrock-diagnoser
| Interface | Purpose |
|---|---|
| DiagnosticsBuilder | Main interface with add() method for adding diagnostics |
| DocumentDiagnosticsBuilder | Extension for document-specific diagnostics |
| DiagnosticSeverity | Severity levels: error, warning, info, hint |
📁 Location: packages/bedrock-diagnoser/src/types/diagnostics-builder.ts
Diagnostics are organized by category:
packages/bedrock-diagnoser/src/diagnostics/
├── behavior-pack/ # Behavior pack diagnostics
│ ├── animation/
│ ├── entity/
│ ├── mcfunction/
│ └── ...
├── resource-pack/ # Resource pack diagnostics
│ ├── animation/
│ ├── sounds/
│ └── ...
├── general/ # Generic validation (integers, floats, etc.)
├── minecraft/ # Minecraft-specific (selectors, effects, etc.)
├── molang/ # Molang expression diagnostics
└── errors/ # Common error utilities
<category>.<subcategory>.<type>.<detail>
| Category | Use For |
|---|---|
behaviorpack |
Behavior pack issues |
resourcepack |
Resource pack issues |
general |
Generic validation (types, formats) |
minecraft |
Minecraft concepts (selectors, effects, tags) |
json |
JSON parsing/validation |
diagnostics |
Internal system issues |
| Suffix | Meaning |
|---|---|
.missing |
Resource/definition not found |
.invalid |
Invalid syntax or value |
.deprecated |
Deprecated feature |
.minimum / .maximum |
Value range violation |
.duplicate |
Duplicate definition |
'behaviorpack.entity.event.missing' // Missing entity event
'resourcepack.animation.missing' // Missing animation
'general.integer.invalid' // Invalid integer
'minecraft.selector.invalid' // Invalid selector
'general.integer.minimum' // Below minimum
'general.integer.maximum' // Above maximumChoose the appropriate directory:
| Type | Directory |
|---|---|
| Behavior pack | diagnostics/behavior-pack/ |
| Resource pack | diagnostics/resource-pack/ |
| General validation | diagnostics/general/ |
| Minecraft-specific | diagnostics/minecraft/ |
Find or create the diagnostic function file:
// Example: packages/bedrock-diagnoser/src/diagnostics/behavior-pack/entity/diagnose.tsUse diagnoser.add() with four parameters:
diagnoser.add(
position, // string path or DocumentLocation
message, // Human-readable error message
severity, // DiagnosticSeverity enum
code // Error code string
);See Severity Levels section.
✅ Good messages:
- Concise and descriptive
- Explain what's wrong
- Suggest fixes when possible
- Include relevant context
- Create test file with problematic code
- Run diagnostic system
- Verify error reported correctly
- Test edge cases
When to use: Issues that will definitely cause runtime problems
Examples:
- Missing required resources
- Invalid syntax Minecraft can't parse
- Type mismatches
- Security vulnerabilities
diagnoser.add(
value,
`Cannot find entity definition: ${id}`,
DiagnosticSeverity.error,
'behaviorpack.entity.missing'
);When to use: Issues that might cause problems or are bad practice
Examples:
- Missing optional resources
- Deprecated features
- Component groups not found
diagnoser.add(
path,
`Event uses deprecated run_command, use queue_command instead`,
DiagnosticSeverity.warning,
'behaviorpack.entity.event.run_command'
);When to use: Suggestions and optimization opportunities
Examples:
- Unnecessary code
- Performance improvements
- Style suggestions
diagnoser.add(
event_id,
"'randomize' only has one entry and can be removed",
DiagnosticSeverity.info,
'behaviorpack.entity.event.randomize.length'
);When to use: Subtle suggestions that don't impact functionality
Examples:
- Code style preferences
- Minor optimizations
| Practice | Example |
|---|---|
| Use consistent codes | Follow category.subcategory.type pattern |
| Be specific | Include problematic value in message |
| Be concise | Keep messages short and clear |
| Suggest fixes | Tell user how to resolve the issue |
| Reuse functions | Use existing utilities like Errors.missing() |
| Anti-pattern | Why |
|---|---|
| Vague messages | "Error" tells user nothing |
| Generic codes | "error" doesn't categorize |
| Missing context | User can't identify the problem |
| Overly long messages | Hard to read in IDE |
// ❌ Bad: Vague
diagnoser.add(value, 'Error', DiagnosticSeverity.error, 'error');
// ✅ Good: Clear and specific
diagnoser.add(
value,
`Cannot find behavior pack animation: ${id}`,
DiagnosticSeverity.error,
'behaviorpack.animation.missing'
);// ❌ Bad: No context
diagnoser.add(value, 'Invalid value', DiagnosticSeverity.error, 'invalid');
// ✅ Good: Shows problematic value
diagnoser.add(
value,
`Invalid integer value: ${value.text}`,
DiagnosticSeverity.error,
'general.integer.invalid'
);// Object property path
diagnoser.add('events/my_event/trigger', message, severity, code);
// Text offset (OffsetWord)
diagnoser.add(value, message, severity, code);
// Document location
diagnoser.add({ line: 10, character: 5 }, message, severity, code);Create reusable functions for common patterns:
export function general_integer_diagnose(
value: Types.OffsetWord,
diagnoser: DiagnosticsBuilder,
range?: { min: number; max: number }
): boolean {
if (General.Integer.is(value.text)) {
if (range) {
const v = Number.parseInt(value.text);
if (v < range.min) {
diagnoser.add(
value,
`The value of ${v} is lower than the allowed minimum: ${range.min}`,
DiagnosticSeverity.error,
'general.integer.minimum'
);
}
if (v > range.max) {
diagnoser.add(
value,
`The value of ${v} is higher than the allowed maximum: ${range.max}`,
DiagnosticSeverity.error,
'general.integer.maximum'
);
}
}
return true;
}
diagnoser.add(
value,
`Invalid integer value: ${value.text}`,
DiagnosticSeverity.error,
'general.integer.invalid'
);
return false;
}// Check for undefined
if (data === undefined) return;
// Handle single values and arrays
const groups = typeof value === 'string' ? [value] : value;Task: Check if boolean value is valid
import { General, Types } from 'bc-minecraft-bedrock-types';
import { DiagnosticsBuilder, DiagnosticSeverity } from '../../types';
export function general_boolean_diagnose(
value: Types.OffsetWord,
diagnoser: DiagnosticsBuilder
): void {
if (General.Boolean.is(value.text)) return;
diagnoser.add(
value,
`Invalid boolean value: ${value.text}`,
DiagnosticSeverity.error,
'general.boolean.invalid'
);
}Task: Verify animation exists
export function diagnose_animation_implementation(
anim_id: string,
user: User,
diagnoser: WithMetadata<DiagnosticsBuilder, MolangMetadata>
): void {
const anim = diagnoser.context
.getProjectData()
.behaviors.animations.get(anim_id, diagnoser.project);
if (anim === undefined) {
return diagnoser.add(
user.id,
`Cannot find behaviors animations definition: ${anim_id}`,
DiagnosticSeverity.error,
'behaviorpack.animations.missing'
);
}
// Continue validation...
}Task: Create reusable component checker
export function component_error<T>(
message: string,
code: string | number
): ComponentCheck<T> {
return (name, _component, _context, diagnoser) => {
diagnoser.add(name, message, DiagnosticSeverity.error, code);
};
}
// Usage
const checks: Record<string, ComponentCheck<Entity>> = {
'minecraft:is_tamed': component_error(
'This component requires rideable entities',
'behaviorpack.entity.component.is_tamed.invalid'
),
};Task: Warn about deprecated properties
if (event.run_command) {
diagnoser.add(
`events/${event_id}`,
`Event uses deprecated run_command, use queue_command instead`,
DiagnosticSeverity.warning,
'behaviorpack.entity.event.run_command'
);
}Task: Multiple validation checks with different error codes
export function minecraft_selector_diagnose(
pattern: ParameterInfo,
value: Types.OffsetWord,
diagnoser: DiagnosticsBuilder
) {
const sel = value.text;
// Validate selector syntax
if (sel.startsWith('@')) {
const selector = Minecraft.Selector.Selector.parse(sel, value.offset);
if (selector === undefined) {
diagnoser.add(
value,
'Invalid selector',
DiagnosticSeverity.error,
'minecraft.selector.invalid'
);
}
return;
}
// Handle fake entities
const name = Text.UnQuote(sel);
if (pattern.options?.allowFakePlayers === false) {
diagnoser.add(
value,
'No fake players / names allowed',
DiagnosticSeverity.error,
'minecraft.selector.invalid'
);
}
}Shorthand for missing resource errors:
import { Errors } from '../..';
const anim = diagnoser.context
.getProjectData()
.behaviors.animations.get(anim_id, diagnoser.project);
if (anim === undefined) {
// Generates code: "behaviorpack.animations.missing"
return Errors.missing('behaviors', 'animations', anim_id, diagnoser);
}For entity component validation:
import { component_error, component_warning } from '../../utility/components/checks';
const component_checks: Record<string, ComponentCheck<T>> = {
'minecraft:my_component': component_error(
'This component requires additional setup',
'behaviorpack.entity.component.my_component.invalid'
),
};- ✅ Create test file in
packages/bedrock-diagnoser/test/ - ✅ Add valid and invalid test cases
- ✅ Verify diagnostic code matches
- ✅ Test edge cases (undefined, empty strings)
import { TestDiagnoser } from '../../../../test/diagnoser';
import { diagnose } from '../src/diagnostics/your-diagnostic';
describe('Your Diagnostic', () => {
it('should report error for invalid value', () => {
const diagnoser = TestDiagnoser.create();
const value = { text: 'invalid', offset: 0 };
diagnose(value, diagnoser);
expect(diagnoser.hasCode('your.diagnostic.code')).toBe(true);
});
});| Resource | Location |
|---|---|
| DiagnosticsBuilder Interface | packages/bedrock-diagnoser/src/types/diagnostics-builder.ts |
| Existing Examples | packages/bedrock-diagnoser/src/diagnostics/ |
| Error Utilities | packages/bedrock-diagnoser/src/diagnostics/errors/ |
| Contributing Guide | CONTRIBUTING.md |
- Check existing diagnostics in similar categories
- Review the Contributing Guide
- Open an issue for discussion
- Join community discussions
Happy Diagnosing! 🔍