Skip to content

[Bug] Heap corruption when host calls execute at AssemblyScript module-init time #6559

@nkuba

Description

@nkuba

Bug report

Summary

When a subgraph's AssemblyScript code invokes graph-ts host-call helpers (e.g. Address.fromString, Bytes.fromHexString) at module-initialization time via top-level const declarations, the graph-node wasm runtime ends up in a corrupted heap state. The corruption is silent until some unrelated handler later in the same subgraph.yaml reads an AscString, at which point graph-node throws:

Attempted to read past end of string content bytes chunk

(thrown from runtime/wasm/src/asc_abi/v0_0_5.rs#L234)

After retries this also surfaces as the related cascade error in InputSchema::entity_type with an empty/garbled name (internal error: unknown name when looking up entity type), because subsequent host calls receive corrupted AscString pointers.

Reproducer

Minimal handler module:

import { Address, Bytes } from "@graphprotocol/graph-ts"
import { Pool } from "../generated/schema"                                                                                                                
  
// These two top-level consts trigger the corruption.                                                                                                     
export const ADDR = Address.fromString("0xd97576d5fed11c7c31095d4fd0af612dc736679b")
export const TOPIC = Bytes.fromHexString("0xaa2dd386ed08047486db39ea1a9e5461b6a95c8bb3ca845cce27a537799a4672")                                            
                                                                                                                                                          
export function handleAnything(/* … */): void {                                                                                                           
  // Any handler that does store.get / store.set later traps with the AscString error,                                                                    
  // even with hardcoded literal arguments:                          
  Pool.load("0x525f049a4494da0a6c87e3c4df55f9929765dc3e")                                                                                                 
}

Workaround

Wrap the host calls in functions and invoke them lazily inside handlers:

function addr(): Address {                                                                                                                                
  return Address.fromString("0xd97576d5fed11c7c31095d4fd0af612dc736679b")
}                                                                                                                                                         
function topic(): Bytes {
  return Bytes.fromHexString("0xaa2dd386ed08047486db39ea1a9e5461b6a95c8bb3ca845cce27a537799a4672")                                                        
}                                                                                                                                                         

Once these are not evaluated at module load, all handlers run cleanly.

Environment

  • graph-node: graphprotocol/graph-node:latest (pulled 2026-05-05; also reproduced on a Goldsky-hosted deployment)
  • graph-cli: tested both 0.96.0 and 0.98.1 (both reproduce)
  • graph-ts: 0.37.0
  • apiVersion: 0.0.9
  • specVersion: 1.3.0
  • Chain: Mezo testnet (EVM). Reproducer transaction: 0xf06b7d247d24a43f86c1f2fc32c7627c1d484e950870465daeca714b37e3fa2d at block 5561094.

Why I believe this is graph-node, not the mapping

  • The wasm only imports store.get, store.set, ethereum.call, log.log, and typeConversion.* (verified via wasm-objdump).
  • All entity-type strings passed to store.get are hardcoded by the graph-cli codegen — they cannot be empty.
  • The trap message comes from graph-node's AscString::from_asc_bytes walking UTF-16LE byte pairs, implying the AscPtr<AscString> it reads has an
    odd byte length — i.e. the AS heap is in a state graph-node doesn't expect.
  • The bug disappears with no other code change when the offending host calls are deferred out of module-init.

Relevant log output

IPFS hash

No response

Subgraph name or link to explorer

No response

Some information to help us out

  • Tick this box if this bug is caused by a regression found in the latest release.
  • Tick this box if this bug is specific to the hosted service.
  • I have searched the issue tracker to make sure this issue is not a duplicate.

OS information

None

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions