gleam-lang/gleam · error

InMemoryFile::into_content called with multiple references

Error message

InMemoryFile::into_content called with multiple references

What it means

`InMemoryFile::into_content` requires sole ownership of the file's shared buffer (an Rc). Rc::try_unwrap fails when clones of the buffer/file still exist, panicking with 'called with multiple references'. Like error 134, this is a consumption-time ownership violation.

Solutions

  1. Ensure no clones of the InMemoryFile/buffer exist when calling into_content.
  2. Take read-only snapshots via borrowing methods instead of cloning the file.
  3. Consume files strictly after all readers have finished (structure code so handles are dropped).
  4. Debug with Rc::strong_count(&buffer) to find lingering clones.

Example fix

// before
let handle = fs.get(&path).cloned();
fs.into_contents(); // panics inside into_content
// after
drop(handle);
fs.into_contents(); // sole reference
Defensive patterns

Strategy: validation

Validate before calling

debug_assert_eq!(std::rc::Rc::strong_count(&buffer), 1, "multiple references; into_content would panic");

Prevention

When it happens

Trigger: Calling `into_content()` (e.g. via InMemoryFileSystem::into_contents) while any clone of the underlying file buffer is alive — clones taken for reads, stored handles, or files cloned out of the FS before consumption.

Common situations: Emitting compiled output from the in-memory filesystem after code elsewhere cloned files for inspection or caching.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


AI-assisted analysis of gleam-lang/gleam@15b07c7830 (2026-09-14). Data as JSON: /api/errors/11c7be67cd0d1fd5. Report an issue: GitHub.

Appendix: source

Thrown at compiler-core/src/io/memory.rs:402

            ..Self::default()
        }
    }

    /// Checks whether this is a directory's entry.
    pub fn is_directory(&self) -> bool {
        matches!(self.node, InMemoryFileNode::Directory)
    }

    /// Returns this file's contents if this is not a directory.
    ///
    /// # Panics
    ///
    /// Panics if this is not the only reference to the underlying files.
    ///
    pub fn into_content(self) -> Option<Content> {
        let buffer = self.node.into_file_buffer()?;
        let contents = Rc::try_unwrap(buffer)
            .expect("InMemoryFile::into_content called with multiple references")
            .into_inner();

        // All null bytes are usually from when a binary file is empty, and
        // aren't particularly useful as text, so we treat them as binary.
        if contents.iter().all(|byte| *byte == 0) {
            return Some(Content::Binary(contents));
        }

        match String::from_utf8(contents) {
            Ok(s) => Some(Content::Text(s)),
            Err(e) => Some(Content::Binary(e.into_bytes())),
        }
    }
}

impl Default for InMemoryFile {
    fn default() -> Self {
        Self {

View on GitHub (pinned to 15b07c7830)