Two related problems in MODE mainnet spawn (spawnWith, connect/src/client/ao-core.js) make it hard to spawn a process on a non-genesis-wasm execution device such as HyperBEAM's native lua@5.3a. Reproducible on @permaweb/aoconnect@0.0.98.
1. execution-device is hardcoded, and overriding it via a tag is case-fragile
spawnWith builds the process params with a hardcoded 'execution-device': 'genesis-wasm@1.0', then spreads ...getTags(args) afterward. Because the spread comes last, a lowercase execution-device tag happens to override the hardcoded value — but the natural Execution-Device casing is a distinct JS object key, so both survive into the message. A HyperBEAM node lowercases and merges duplicate tag names, yielding execution-device = "genesis-wasm@1.0", "lua@5.3a", and rejects the process with device_not_loadable at dev_process:compute.
So the only way to spawn a native-lua process today is the non-obvious trick of an all-lowercase execution-device tag; the intuitive capitalized tag produces a broken process.
const ao = connect({ MODE: 'mainnet', URL: NODE, signer });
await ao.spawn({ module: MODULE_TXID, scheduler: NODE_ADDR,
tags: [{ name: 'Execution-Device', value: 'lua@5.3a' }] });
// -> spawns with execution-device = "genesis-wasm@1.0", "lua@5.3a"
// -> device_not_loadable on first compute
2. A map-valued module is silently stringified to "[object Object]"
Module: module is placed directly into the params and tag values are coerced with String(value), so a map module ({ 'content-type': 'application/lua', body: '<src>' }) serializes to the literal string "[object Object]". The process spawns with a garbage module and every compute fails, with no error at spawn time.
await ao.spawn({ scheduler: NODE_ADDR,
module: { 'content-type': 'application/lua', body: 'function compute() end' } });
// -> spawned process's `module` = "[object Object]"
Proposed fix
- Make
execution-device a first-class option (EXECUTION_DEVICE env / args.executionDevice), mirroring how module and authority are already resolved, so callers set it directly without depending on tag casing.
- Throw when
module is not a string, pointing at the upload-and-reference-by-id flow (map/inline modules aren't encodable on the ans104 signing path mainnet spawn uses).
Two related problems in MODE
mainnetspawn(spawnWith,connect/src/client/ao-core.js) make it hard to spawn a process on a non-genesis-wasmexecution device such as HyperBEAM's nativelua@5.3a. Reproducible on@permaweb/aoconnect@0.0.98.1.
execution-deviceis hardcoded, and overriding it via a tag is case-fragilespawnWithbuilds the process params with a hardcoded'execution-device': 'genesis-wasm@1.0', then spreads...getTags(args)afterward. Because the spread comes last, a lowercaseexecution-devicetag happens to override the hardcoded value — but the naturalExecution-Devicecasing is a distinct JS object key, so both survive into the message. A HyperBEAM node lowercases and merges duplicate tag names, yieldingexecution-device = "genesis-wasm@1.0", "lua@5.3a", and rejects the process withdevice_not_loadableatdev_process:compute.So the only way to spawn a native-lua process today is the non-obvious trick of an all-lowercase
execution-devicetag; the intuitive capitalized tag produces a broken process.2. A map-valued
moduleis silently stringified to"[object Object]"Module: moduleis placed directly into the params and tag values are coerced withString(value), so a map module ({ 'content-type': 'application/lua', body: '<src>' }) serializes to the literal string"[object Object]". The process spawns with a garbage module and every compute fails, with no error at spawn time.Proposed fix
execution-devicea first-class option (EXECUTION_DEVICEenv /args.executionDevice), mirroring howmoduleandauthorityare already resolved, so callers set it directly without depending on tag casing.moduleis not a string, pointing at the upload-and-reference-by-id flow (map/inline modules aren't encodable on the ans104 signing path mainnet spawn uses).