Diagnostic Error Codes
Tsonic uses diagnostic codes in the format TSNxxxx to identify specific errors.
Error Code Ranges
| Range | Category |
|---|---|
| TSN1xxx | Module resolution and imports |
| TSN2xxx | Type system errors |
| TSN3xxx | C# identifier and keyword errors |
| TSN4xxx | .NET interop errors |
| TSN5xxx | NativeAOT and runtime errors |
| TSN6xxx | Internal compiler errors |
| TSN7xxx | Language semantics and validation |
| TSN9xxx | Metadata and bindings loading |
TSN1xxx: Module Resolution
TSN1001: Missing .ts Extension
Local imports must use the .ts extension.
// Wrong
import { User } from "./models/User";
// Correct
import { User } from "./models/User.js";
TSN1002: Circular Dependency
Modules have a circular import dependency.
// A.ts imports B.ts
// B.ts imports A.ts // Circular
Fix: Extract shared code to a third module.
TSN1003: Case Mismatch
Import path case doesn't match file on disk.
// File: ./models/User.ts
import { User } from "./models/user.js"; // Wrong case
TSN1004: Module Not Found
Referenced module doesn't exist.
TSN1005: Conflicting Exports
Multiple modules export the same name creating ambiguity.
TSN1006: Invalid Namespace
The import specifier doesn't form a valid namespace.
TSN2xxx: Type System
TSN2001: Unsupported TypeScript Feature
Feature not supported in Tsonic.
// Examples of unsupported features:
type Readonly<T> = { readonly [K in keyof T]: T[K] }; // Mapped types
type Result<T> = T extends string ? string : number; // Conditional types
TSN2002: Invalid Type Mapping
Type cannot be mapped to C#.
TSN2003: Name Conflict
File name conflicts with an exported member name.
// File: User.ts
export class User {} // Conflicts with file name
Fix: Rename either the file or the export.
TSN3xxx: C# Identifiers
TSN3001: C# Reserved Keyword
Identifier uses a C# reserved keyword.
// "class", "namespace", "event", etc. are reserved in C#
const event = "click"; // Error
TSN3002: Invalid C# Identifier
Identifier cannot be used in C#.
TSN3011: Promise Chaining Not Supported
.then(), .catch(), .finally() are not supported.
// Wrong
promise.then((result) => doSomething(result));
// Correct - use async/await
const result = await promise;
doSomething(result);
TSN4xxx: .NET Interop
TSN4001: .NET Interop Error
Error accessing .NET types or members.
TSN4002: Missing .NET Type Declaration
.NET type is used but not declared in typings.
TSN5xxx: NativeAOT/Runtime
TSN5001: NativeAOT Limitation
Code uses feature incompatible with NativeAOT.
TSN5002: Runtime Implementation Missing
Required runtime feature not available.
TSN6xxx: Internal Compiler
TSN6001: Internal Compiler Error
Unexpected error in compilation. Please report this as a bug.
TSN7xxx: Language Semantics
TSN7101: Recursive Mapped Types
Recursive mapped types are not supported.
TSN7102: Conditional Types with Infer
Conditional types using infer are not supported.
TSN7103: this Typing
this type expressions are not supported.
TSN7104: Generic Constructor Constraints
Generic constructor constraints with rest parameters are not supported.
TSN7105: Type Specialization
Cannot determine required type specializations for generics.
TSN7201: Recursive Structural Alias
Recursive structural type aliases are not supported.
TSN7202: Conditional Alias Resolution
Conditional type alias cannot be resolved statically.
TSN7203: Symbol Keys
Symbol keys in objects are not supported.
TSN7204: Variadic Generic Interface
Variadic generic interfaces are not supported.
TSN7301: Implements Nominalized Interface
Classes cannot implement TypeScript interfaces directly.
interface Printable {
print(): void;
}
class Document implements Printable {
// Error
print(): void {}
}
In Tsonic, TypeScript interfaces become C# classes. Use extends instead:
class Document extends Printable {
// Correct
print(): void {}
}
Or use composition/duck typing.
TSN7401: any Type Not Supported
The any type cannot be used. Provide explicit types.
// Wrong
function process(data: any) {}
// Correct
function process(data: unknown) {}
function process(data: string) {}
TSN7403: Object Literal Requires Type
Object literals need a contextual nominal type, OR must be eligible for auto-synthesis.
Auto-synthesized (no error):
const point = { x: 1, y: 2 }; // OK - synthesizes __Anon_file_1_1
const handler = { process: (x: number) => x * 2 }; // OK - arrow functions allowed
const config = { name: "test", count: 42 }; // OK - property assignments
Requires explicit type (error):
const obj = {
foo() {
return 1;
},
}; // Error - method shorthand not allowed
const obj = {
get x() {
return 1;
},
}; // Error - getters not allowed
Use arrow function syntax for function properties, or provide explicit type annotation:
interface Point {
x: number;
y: number;
}
const obj: Point = { x: 1, y: 2 }; // Explicit type annotation
TSN7405: Untyped Lambda Parameter
Lambda parameters require explicit type annotations when contextual type cannot be inferred.
Contextual inference works (no error):
const numbers = [1, 2, 3];
const doubled = numbers.map((x) => x * 2); // OK - x inferred as number
const filtered = items.filter((item) => item.active); // OK - item inferred
const callback: (n: number) => number = (x) => x * 2; // OK - typed variable
Requires explicit types (error):
const fn = (x) => x * 2; // Error - no contextual type available
// Fix: Add explicit type annotation
const fn = (x: number): number => x * 2;
TSN7413: Dictionary Key Type
Dictionary keys must be string or number type.
// OK
const byName: Record<string, User> = {};
const byId: Record<number, User> = {};
interface StringDict {
[key: string]: number;
}
interface NumberDict {
[key: number]: string;
}
// Error
const bySymbol: Record<symbol, User> = {}; // Symbols not supported
TSN7406: Mapped Types Not Supported
Mapped types (utility types that transform properties) are not supported.
// Error
type ReadonlyUser = Readonly<User>;
type PartialConfig = Partial<Config>;
type RequiredFields = Required<OptionalFields>;
// Fix: Create explicit interface with desired properties
interface ReadonlyUser {
readonly name: string;
readonly email: string;
}
TSN7407: Conditional Types Not Supported
Conditional types are not supported.
// Error
type Result<T> = T extends string ? StringResult : OtherResult;
type NonNullable<T> = T extends null | undefined ? never : T;
// Fix: Use explicit type unions or separate types
type StringResult = { kind: "string"; value: string };
type OtherResult = { kind: "other"; value: unknown };
TSN7410: Intersection Types Not Supported
Intersection types (A & B) are not supported.
// Error
type Combined = TypeA & TypeB;
type WithTimestamp = User & { timestamp: number };
// Fix: Create explicit interface combining both types
interface Combined {
// Include all members from TypeA
// Include all members from TypeB
}
interface UserWithTimestamp {
name: string;
email: string;
timestamp: number;
}
TSN7408: Mixed Variadic Tuples Not Supported
Variadic tuple types with mixed elements are not supported.
// Error
type Mixed = [string, ...number[]];
// Fix: Use a regular array or fixed tuple
type Fixed = [string, number, number];
type NumberArray = number[];
TSN7409: 'infer' Keyword Not Supported
The infer keyword in conditional types is not supported.
// Error
type UnwrapPromise<T> = T extends Promise<infer U> ? U : T;
// Fix: Use explicit type parameters or overloads
TSN7414: Type Cannot Be Represented
The type cannot be represented in the compiler's type subset.
// Error: Complex types that can't map to C#
type Complex = { [K in keyof T]: T[K] };
// Fix: Use simpler, explicit type definitions
TSN7415: Nullable Union with Unconstrained Generic
Nullable unions with unconstrained generic type parameters cannot be represented in C#.
// Error
function getValue<T>(value: T | null): T {
return value ?? getDefault();
}
// The problem: In C#, T? for an unconstrained type parameter T
// does not provide nullability for value types.
// If T is int, then T? is still int (not Nullable<int>)
Why this happens:
In C#, nullable generics work differently based on constraints:
T? where T : struct→Nullable<T>(works for value types)T? where T : class→ nullable reference (works for reference types)T?with no constraint → justTfor value types (no nullability!)
Fix options:
- Use
object | nullto box the value:
function getValue<T>(value: object | null): T {
return (value ?? getDefault()) as T;
}
- Add a constraint if T is always a reference type:
function getValue<T extends object>(value: T | null): T {
return value ?? getDefault();
}
- Use
structconstraint if T is always a value type:
function getValue<T extends struct>(value: T | null): T {
return value ?? getDefault();
}
See also: Troubleshooting Guide for more patterns.
TSN7417: Empty Array Literal Requires Type
Empty array literals must have a type annotation. Tsonic cannot infer the element type of an empty array.
// Error
const arr = []; // What type are the elements?
// Correct
const arr: number[] = [];
const strings: string[] = [];
const items: Array<User> = [];
Why this is required:
In TypeScript, [] is inferred as any[] or contextually typed. In Tsonic, we compile to C# where arrays have fixed element types at compile time. Without a type annotation, we cannot determine what C# type to generate.
Patterns that work without annotation:
// Non-empty arrays infer the type from elements
const numbers = [1, 2, 3]; // Tsonic infers: int[]
const mixed = [1, 2.5, 3]; // Inferred as double[]
const largeNumbers = [1, 2147483648]; // Inferred as long[] (element exceeds int range)
// Function return types provide context
function getNumbers(): number[] {
return []; // OK - contextual type from return type
}
TSN7418: Invalid char Value
char represents the CLR type System.Char (imported from @tsonic/core/types.js).
TypeScript models char as string for compatibility, so Tsonic validates char during compilation:
- A
charvalue must be a single-character string literal (including escapes like"\\n"), or - A value that is already typed as
char(for example, from APIs that returnchar).
import { char } from "@tsonic/core/types.js";
function takesChar(c: char): void {}
takesChar("A"); // OK
// takesChar("AB"); // TSN7418 (multi-character literal)
const s = "hello";
// takesChar(s); // TSN7418 (not a literal / not char-typed)
takesChar(s[0]); // OK (context expects char)
Fix: Use a single-character literal in a char position, or obtain a char from an API returning char (for example System.Char.parse("Q")).
TSN7420: ref/out/In Are Parameter Modifiers
ref, out, and In are parameter passing modifiers, not types.
// Error
function foo(x: ref<number>) {} // Wrong - ref is not a type
// Correct: Use type annotation on the .NET side
// These are handled via metadata, not TypeScript syntax
TSN7421: Anonymous Object Type Not Lowered
Internal compiler error indicating an anonymous object type was not properly lowered to a synthesized class. This is a compiler bug - please report it.
TSN7422: Object Rest Requires Finite Object Shape
Object rest patterns (...rest) require a known, finite set of properties to determine what goes in the rest object.
// Error: Cannot determine rest shape
function process(obj: Record<string, unknown>): void {
const { id, ...rest } = obj; // Error - infinite keys possible
}
// OK: Finite shape known
interface User {
id: number;
name: string;
email: string;
}
function process(user: User): void {
const { id, ...rest } = user; // OK - rest is { name, email }
}
TSN7423: Unsupported Destructuring Pattern
The destructuring pattern is not supported. This may include:
- Computed property keys in destructuring
- Patterns that cannot be lowered to C#
TSN7430: Arrow Function Requires Explicit Types (Escape Hatch)
Arrow functions can only infer parameter and return types from context when they meet the "simple arrow" criteria:
- Not async
- Expression body (not block body)
- All parameters are simple identifiers (no destructuring)
- No default parameter values
- No rest parameters
Contextual inference works (no error):
const numbers = [1, 2, 3];
const doubled = numbers.map((x) => x * 2); // OK - simple arrow with context
const filtered = items.filter((item) => item.active); // OK
const callback: (n: number) => number = (x) => x * 2; // OK - typed variable
Requires explicit types (error):
// No contextual type
const fn = (x) => x * 2; // Error - no context for inference
// Block body (not expression body)
items.map((x) => {
const y = x + 1;
return y;
}); // Error - block body requires explicit return type
// Async arrow
items.map(async (x) => await fetch(x)); // Error - async requires explicit types
// Destructuring pattern
items.map(({ id, name }) => id + name); // Error - destructuring requires explicit types
// Default parameter
items.map((x = 0) => x * 2); // Error - defaults require explicit types
// Rest parameter
items.map((...args) => args.length); // Error - rest requires explicit types
Fix: Add explicit type annotations:
// For block bodies, add return type
items.map((x): number => {
const y = x + 1;
return y;
});
// For complex arrows, fully annotate
const fn = (x: number): number => x * 2;
TSN7431: Cannot Infer Arrow Return Type
The arrow function's return type cannot be inferred safely. This occurs when the body expression produces an unsafe type (any, unknown, or anonymous structural type).
// Error: Return type is 'any' or 'unknown'
items.map((x) => someAnyFunction(x)); // Cannot infer return type
// Error: Return type is anonymous object type
items.map((x) => ({ id: x, name: "test" })); // Anonymous type needs nominal type
Fix: Provide explicit return type annotation:
interface Result {
id: number;
name: string;
}
items.map((x): Result => ({ id: x, name: "test" }));
TSN5xxx: Numeric Proof Errors
TSN5101-TSN5110: Numeric Type Errors
Errors related to numeric type narrowing and proof:
| Code | Error |
|---|---|
| TSN5101 | Cannot prove numeric narrowing is safe |
| TSN5102 | Numeric literal out of range |
| TSN5103 | Binary operation produces wrong numeric type |
| TSN5104 | Cannot narrow from source to target type |
| TSN5105 | Unproven numeric type at parameter boundary |
| TSN5106 | Unproven numeric type at return boundary |
| TSN5107 | Array index must be Int32 |
| TSN5108 | Value exceeds JS safe integer range |
| TSN5109 | Computed access kind not classified (ICE) |
| TSN5110 | Integer literal cannot be implicitly converted |
TSN6xxx: Yield Lowering Errors
TSN6101: Yield Expression in Unsupported Position
The yield expression is in a position that cannot be lowered to C# iterators.
// Error: yield in expression position
const x = (yield 1) + 2; // Not supported
// OK: yield as statement
yield 1;
const x = yield; // Bidirectional yield
TSN9xxx: Metadata Loading
TSN9001-TSN9018: Metadata Errors
Errors loading .metadata.json files:
| Code | Error |
|---|---|
| TSN9001 | Metadata file not found |
| TSN9002 | Failed to read metadata file |
| TSN9003 | Invalid JSON in metadata file |
| TSN9004 | Metadata file must be an object |
| TSN9005 | Missing or invalid 'namespace' field |
| TSN9006 | Missing or invalid 'contributingAssemblies' field |
| TSN9007 | All 'contributingAssemblies' must be strings |
| TSN9008 | Missing or invalid 'types' field |
| TSN9009 | Invalid type: must be an object |
| TSN9010 | Invalid type: missing or invalid field |
| TSN9011 | Invalid type: 'kind' must be one of ... |
| TSN9012 | Invalid type: 'accessibility' must be one of ... |
| TSN9013 | Invalid type: field must be a boolean |
| TSN9014 | Invalid type: 'arity' must be a non-negative number |
| TSN9015 | Invalid type: field must be an array |
| TSN9016 | Metadata directory not found |
| TSN9017 | Not a directory |
| TSN9018 | No .metadata.json files found |
TSN9101-TSN9114: Bindings Errors
Errors loading .bindings.json files:
| Code | Error |
|---|---|
| TSN9101 | Bindings file not found |
| TSN9102 | Failed to read bindings file |
| TSN9103 | Invalid JSON in bindings file |
| TSN9104 | Bindings file must be an object |
| TSN9105 | Missing or invalid 'namespace' field |
| TSN9106 | Missing or invalid 'types' field |
| TSN9107 | Invalid type binding: must be an object |
| TSN9108 | Invalid type binding: missing or invalid field |
| TSN9109 | Invalid type binding: 'metadataToken' must be a number |
| TSN9110 | Invalid type binding: V1 field must be an array if present |
| TSN9111 | Invalid type binding: V2 field must be an array if present |
| TSN9112 | Bindings directory not found |
| TSN9113 | Not a directory |
| TSN9114 | No .bindings.json files found |
Getting Help
If you encounter an error:
- Check this guide for the specific error code
- Check the troubleshooting guide
- Search GitHub issues
- Open a new issue with:
- Error code and message
- Minimal reproduction case
- Tsonic version (
tsonic --version)