-
Notifications
You must be signed in to change notification settings - Fork 55
Open
Description
Bug description
Description
When encoding a MapSchema containing nested Schema instances, encodeValue in EncodeOperation.ts:37 receives undefined as the type parameter, causing a crash on type[Symbol.metadata].
The @type() decorators run correctly — Symbol.metadata is populated on all classes (verified via logging). The crash happens at encode time, not at decoration time.
Environment
@colyseus/schema: 3.0.76colyseus: 0.16.5- Node.js: 24.13.0
- TypeScript: 5.9.3
- Runtime: tsx 4.21.0 with
--no-experimental-strip-types(forces esbuild, which correctly handlesexperimentalDecorators) - tsconfig:
"experimentalDecorators": true
Error
TypeError: Cannot read properties of undefined (reading 'Symbol(Symbol.metadata)')
at encodeValue (EncodeOperation.ts:37:20)
at encodeKeyValueOperation (EncodeOperation.ts:150:5)
at Encoder.encode (Encoder.ts:119:17)
at Encoder.encodeAll (Encoder.ts:155:21)The crash is at this line in EncodeOperation.ts:37:
} else if (type[Symbol.metadata] !== undefined) {where type is undefined.
Notes
- Encoding works fine with no entries in the MapSchema — the crash only happens when encoding a map entry (ADD operation).
- All class metadata is correctly populated (decorators run successfully).
- @colyseus/schema@2.0.37 does not have this issue — MapSchema encoding works correctly there.
- This may be related to how Encoder resolves the child type of a MapSchema before passing it to encodeValue.
Optional: Minimal reproduction
Minimal Reproduction
import { Schema, type, MapSchema, Encoder } from '@colyseus/schema'
class Player extends Schema {
@type('string') sessionId: string = ''
@type('float32') x: number = 0
}
class GameState extends Schema {
@type({ map: Player }) players = new MapSchema<Player>()
@type('string') mapId: string = ''
}
// Verify metadata is populated correctly
console.log('Player metadata:', (Player as any)[Symbol.metadata])
// → { '0': { type: 'string', index: 0, name: 'sessionId' }, '1': { type: 'float32', index: 1, name: 'x' } }
console.log('GameState metadata:', (GameState as any)[Symbol.metadata])
// → { '0': { type: { map: [class Player] }, index: 0, name: 'players' }, '1': { type: 'string', index: 1, name: 'mapId' } }
const state = new GameState()
const encoder = new Encoder(state)
// ✅ This works — empty state
encoder.encodeAll()
// Add a player to the map
const player = new Player()
player.sessionId = 'abc'
player.x = 100
state.players.set('abc', player)
// ❌ This crashes
encoder.encode()Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels