{"record":{"id":"54e64271047ad9d4","repo":"BoundaryML/baml","slug":"heapptr-is-a-runtime-only-pointer-and-must-not-be-serialized","errorCode":null,"errorMessage":"HeapPtr is a runtime-only pointer and must not be serialized","messagePattern":"HeapPtr is a runtime-only pointer and must not be serialized","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"baml_language/crates/bex_vm_types/src/heap_ptr.rs","lineNumber":163,"sourceCode":"    #[cfg(feature = \"heap_debug\")]\n    #[inline]\n    pub fn epoch(self) -> u32 {\n        self.epoch\n    }\n}\n\n// `HeapPtr` is a runtime-only address into the live heap. It must never\n// reach a serialized payload (e.g. a borsh-encoded `Program` in a pack\n// envelope) — the addresses are meaningless outside the originating\n// process, and a deserialized non-null `HeapPtr` would be undefined\n// behavior on first deref. The borsh impls below therefore *fail* at the\n// boundary instead of round-tripping to `null()`: every type the compiler\n// actually puts into a serialized `Program` (`Object::{Function, Class,\n// Enum, String}`) is HeapPtr-free, so any path that does encounter one\n// reflects a real bug we want to surface immediately rather than mask.\nimpl BorshSerialize for HeapPtr {\n    fn serialize<W: std::io::Write>(&self, _writer: &mut W) -> std::io::Result<()> {\n        Err(std::io::Error::new(\n            std::io::ErrorKind::InvalidData,\n            \"HeapPtr is a runtime-only pointer and must not be serialized\",\n        ))\n    }\n}\n\nimpl BorshDeserialize for HeapPtr {\n    fn deserialize_reader<R: std::io::Read>(_reader: &mut R) -> std::io::Result<Self> {\n        Err(std::io::Error::new(\n            std::io::ErrorKind::InvalidData,\n            \"HeapPtr cannot be deserialized: runtime pointer leaked into serialized data\",\n        ))\n    }\n}\n\nimpl PartialEq for HeapPtr {\n    fn eq(&self, other: &Self) -> bool {\n        self.ptr == other.ptr","sourceCodeStart":145,"sourceCodeEnd":181,"githubUrl":"https://github.com/BoundaryML/baml/blob/bd85ce9dee1463ff04d27efd20531013a4ff46c1/baml_language/crates/bex_vm_types/src/heap_ptr.rs#L145-L181","documentation":"HeapPtr's BorshSerialize impl is intentionally a hard failure: a HeapPtr is a runtime-only heap pointer and must never appear in serialized data (a compiled Program). The VM deliberately rejects serialization of any structure containing one so a genuine bug is surfaced immediately rather than silently round-tripping a meaningless pointer.","triggerScenarios":"Calling borsh serialization on a runtime object graph that still contains HeapPtr-backed values (e.g. attempting to persist/serialize live VM state or an object not meant for compiled programs).","commonSituations":"Trying to cache or ship serialized VM heap state; a compiler/VM bug placing a runtime-only object into the serialized Program; custom tooling serializing Value graphs that were never supposed to leave the runtime.","solutions":["Stop serializing live VM/runtime objects; only serialize the compiler-produced Program types (Object::{Function, Class, Enum, String}) which are HeapPtr-free by design.","Audit the type being serialized for accidental inclusion of runtime pointers (heap values, futures).","If you hit this from normal program compilation, report it — it indicates an internal invariant violation where a runtime pointer leaked into the compiled artifact.","Strip/detach runtime-only fields before serializing your own structures."],"exampleFix":"// before: serializing a runtime struct that embeds a HeapPtr\n#[derive(BorshSerialize)]\nstruct Snapshot { obj: HeapPtr }\n\n// after: serialize only HeapPtr-free Program types\n#[derive(BorshSerialize)]\nstruct Snapshot { name: Object_String }","handlingStrategy":"type-guard","validationCode":"// Reject runtime graphs containing HeapPtr before attempting serialization\nfn serializable_check(v: &VmValue) -> bool {\n    !matches!(v, VmValue::Heap(_))\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Serialize only compiler-produced Program types (Object::{Function, Class, Enum, String}).","Never attempt to persist live VM heap state or runtime object graphs.","Audit custom serialization paths for embedded HeapPtr fields.","Treat occurrences as bugs and report them rather than working around."],"tags":["borsh","serialization","heap-pointer","invariant"],"backgroundTag":"internal-invariant-violation","analyzedSha":"bd85ce9dee1463ff04d27efd20531013a4ff46c1","analyzedAt":"2026-09-12T03:38:25.718Z","contentChangedAt":"2026-09-12T03:38:25.718Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}