Error Diagnosis Guide
When a PCD program fails certification, the compiler aborts with a diagnostic message. This guide explains every error type and how to fix it.
How Certification Works
The CMF (Coherence Metric Framework) computes 7 metrics for your program. If any metric is out of bounds, or if the master metric Φ_c ≠ 1.000, compilation is aborted — not warned.
brikc check broken.pcd
# ✗ Φ_c = 0.875 (required: 1.000)
# ✗ δ = 0.125 (1 unused input)
# Compilation aborted.
What it means: Your function declares parameters that are never used.
// BAD: parameter `b` is never used
fn add_one(a, b) {
return a + 1;
}
Diagnostic:
δ = 0.500 (1 of 2 inputs unused)
Φ_c = 0.500 != 1.000
Fix: Remove the unused parameter, or use it:
// GOOD: both parameters used
fn add(a, b) {
return a + b;
}
// Or remove unused parameter
fn add_one(a) {
return a + 1;
}
If you intentionally need to ignore a parameter (e.g., for interface compatibility), prefix it with _:fn handler(event, _context) {
return process(event);
}
The _ prefix tells the CMF to exclude it from the unused input count.
Error: Unreachable Code Paths
What it means: Some code paths never execute, indicating dead branches.
// BAD: the else branch after return is unreachable
fn check(x) {
if (x > 0) {
return "positive";
}
return "non-positive";
let dead = "this never executes"; // unreachable!
}
Fix: Remove dead code after return or OUTPUT:
fn check(x) {
if (x > 0) {
return "positive";
}
return "non-positive";
}
Error: Missing OUTPUT on Some Paths
What it means: Not all control flow paths lead to an OUTPUT or return.
// BAD: what if x == 0?
PC classify {
let x = MC_63.ENV("ARGV_1");
if (x > 0) {
OUTPUT "positive";
}
if (x < 0) {
OUTPUT "negative";
}
// Falls through with no OUTPUT when x == 0!
}
Diagnostic:
Φ_c < 1.000: not all paths produce output
Fix: Add a final OUTPUT that catches all remaining cases:
PC classify {
let x = MC_63.ENV("ARGV_1");
if (x > 0) {
OUTPUT "positive";
}
if (x < 0) {
OUTPUT "negative";
}
OUTPUT "zero"; // catches x == 0
}
Error: Type Mismatch at Monomer Boundary
What it means: You passed a value of the wrong type to a monomer.
// BAD: MC_00.ADD8 expects numbers, not strings
let result = MC_00.ADD8("hello", 5);
Diagnostic:
Type error: MC_00.ADD8 expects (u8, u8), got (string, i64)
Fix: Ensure argument types match the monomer’s signature. See the Monomer Reference for exact signatures.
Error: DIV8 Not Destructured
What it means: MC_03.DIV8 returns a tuple (quotient, remainder), and you’re treating it as a single value.
// BAD: DIV8 returns a tuple
let result = MC_03.DIV8(10, 3);
let doubled = result * 2; // Error: can't multiply a tuple
Diagnostic:
Type error: expected i64, got Tuple([i64, i64])
Fix: Always destructure DIV8:
let (q, r) = MC_03.DIV8(10, 3);
let doubled = q * 2; // OK: q is i64
Error: Division by Zero
What it means: MC_03.DIV8 or MC_04.MOD8 received 0 as the divisor.
let (q, r) = MC_03.DIV8(10, 0); // Runtime error
Fix: Guard against zero before dividing:
fn safe_div(a, b) {
if (b == 0) {
return (0, 0);
}
return MC_03.DIV8(a, b);
}
Or use try/catch:
try {
let (q, r) = MC_03.DIV8(a, b);
OUTPUT q;
} catch (err) {
OUTPUT 0;
}
Error: MAX_DEPTH Exceeded
What it means: Your program has more than 256 levels of nesting.
// BAD: deeply nested ifs exceed MAX_DEPTH=256
if (a) { if (b) { if (c) { ... // 257+ levels
Diagnostic:
Parser error: MAX_DEPTH (256) exceeded at line N
Fix: Flatten nested logic using functions:
fn check_level_1(x) {
// handle first batch of checks
return intermediate_result;
}
fn check_level_2(x) {
let r1 = check_level_1(x);
// handle second batch
return final_result;
}
Error: Circular Import
What it means: Module A imports B, and B imports A (directly or transitively).
a.pcd imports b.pcd
b.pcd imports a.pcd → circular!
Diagnostic:
Import error: circular dependency detected: a.pcd → b.pcd → a.pcd
Fix: Extract shared code into a third module:
common.pcd ← shared functions
a.pcd imports common.pcd
b.pcd imports common.pcd
Error: While Loop SSA Bug
What it means: Variables inside a while loop body don’t update correctly across iterations.
// BUGGY: pos may not update due to WhileLoop SSA bug
let pos = 0;
while (pos < max) {
let pos = pos + 1; // May read stale value!
}
Fix: Replace while with loop(N) + if:
let pos = 0;
loop(max) as _i {
if (pos < max) {
let pos = pos + 1; // Works correctly with loop(N)
}
}
This is a known limitation of the current planner. The while SSA bug captures variable versions before the loop body instead of after. Always use loop(N) in production code.
Error: Out of Bounds Array Access
let arr = [1, 2, 3];
let x = arr[5]; // Runtime error: index 5 out of bounds (len=3)
Fix: Check length before accessing:
let arr = [1, 2, 3];
let idx = 5;
if (idx < len(arr)) {
let x = arr[idx];
} else {
// handle out of bounds
}
Or use try/catch:
try {
let x = arr[idx];
} catch (err) {
let x = 0; // default value
}
Error: String Index Out of Bounds
let s = "hello";
let ch = MC_45.CHAR_AT(s, 10); // Runtime error
Fix: Always check MC_43.LEN first:
let s = "hello";
let idx = 10;
let slen = MC_43.LEN(s);
if (idx < slen) {
let ch = MC_45.CHAR_AT(s, idx);
} else {
let ch = "";
}
Error: Unresolved Import
import "stdlib/nonexistent.pcd"; // File not found
Diagnostic:
Import error: file not found: stdlib/nonexistent.pcd
Fix: Check that the file exists and the path is correct. Available stdlib modules:
| Module | Path |
|---|
| math | stdlib/math.pcd |
| string | stdlib/string.pcd |
| array | stdlib/array.pcd |
| io | stdlib/io.pcd |
| fmt | stdlib/fmt.pcd |
| json | stdlib/json.pcd |
Reading CMF Output
When brikc check outputs the full CMF profile, here’s how to read it:
{
"cmf": {
"e": 4, // Operational complexity: 4 edges in graph (OK)
"h": 0.44, // Signature distance: moderate type transformation (OK)
"s": 0.000, // Structural entropy: no branches (excellent)
"c": 1, // Cyclomatic complexity: 1 path (excellent)
"t": 0, // Termination depth: no loops (excellent)
"δ": 0.000, // Unused inputs: none (required for Ω=1)
"Φ_c": 1.000 // Closure: certified!
},
"omega": 1
}
Red flags to look for:
δ > 0 — you have unused parameters
Φ_c < 1.000 — the circuit is not closed; check δ and ensure all paths produce output
- Very high
s — excessive branching; consider simplifying control flow
- Very high
t — deep loop nesting; consider flattening with functions
Quick Troubleshooting Table
| Symptom | Likely Cause | Fix |
|---|
Φ_c < 1.000 | Unused inputs or missing OUTPUT paths | Remove unused params, add fallback OUTPUT |
δ > 0 | Unused function parameters | Remove or prefix with _ |
| Type error at monomer call | Wrong argument types | Check Monomer Reference |
Tuple type mismatch | Forgot to destructure DIV8 | Use let (q, r) = MC_03.DIV8(...) |
| Parser MAX_DEPTH | Too many nested blocks | Extract into functions |
| While loop vars don’t update | WhileLoop SSA bug | Use loop(N) instead |
| Circular import | A imports B, B imports A | Extract shared code to third module |
| Runtime crash | Division by zero or OOB access | Guard with if or try/catch |