{"record":{"id":"56c2031c50dde230","repo":"neondatabase/neon","slug":"could-not-find-memory-subsystem","errorCode":null,"errorMessage":"could not find memory subsystem","messagePattern":"could not find memory subsystem","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"libs/vm_monitor/src/cgroup.rs","lineNumber":161,"sourceCode":"\n            updates\n                .send((now, summary))\n                .context(\"failed to send MemoryHistory\")?;\n        }\n\n        unreachable!()\n    }\n\n    /// Get a handle on the memory subsystem.\n    fn memory(&self) -> anyhow::Result<&MemController> {\n        self.cgroup\n            .subsystems()\n            .iter()\n            .find_map(|sub| match sub {\n                Subsystem::Mem(c) => Some(c),\n                _ => None,\n            })\n            .ok_or_else(|| anyhow!(\"could not find memory subsystem\"))\n    }\n\n    /// Given a handle on the memory subsystem, returns the current memory information\n    fn memory_usage(mem_controller: &MemController) -> MemoryStatus {\n        let stat = mem_controller.memory_stat().stat;\n        MemoryStatus {\n            non_reclaimable: stat.active_anon + stat.inactive_anon,\n        }\n    }\n}\n\n// Helper function for `CgroupWatcher::watch`\nfn ring_buf_recent_values_iter<T>(\n    buf: &[T],\n    last_value_idx: usize,\n    count: usize,\n) -> impl '_ + Iterator<Item = &T> {\n    // Assertion carried over from `CgroupWatcher::watch`, to make the logic in this function","sourceCodeStart":143,"sourceCodeEnd":179,"githubUrl":"https://github.com/neondatabase/neon/blob/8f60b04da47ffefe0e52bda2440134b42874eb75/libs/vm_monitor/src/cgroup.rs#L143-L179","documentation":"After loading the cgroup, CgroupWatcher::memory looks up the memory controller (MemController) among the cgroup's subsystems; if none is attached, this error is returned. On cgroup v2 the memory controller must be present in the cgroup's controllers and enabled by the parent's cgroup.subtree_control.","triggerScenarios":"Kernel booted with cgroup_disable=memory; the target cgroup's parent has not enabled +memory in cgroup.subtree_control; containers without the memory controller delegated to them.","commonSituations":"Hardened kernels disabling the memory controller; systemd slices created without Delegate=memory; restricted container runtimes.","solutions":["Remove cgroup_disable=memory from the kernel cmdline and reboot","Enable the controller for the subtree: echo +memory > /sys/fs/cgroup/<parent>/cgroup.subtree_control","For containers, delegate the memory controller in the runtime/systemd unit (Delegate=memory)"],"exampleFix":"# before\nGRUB_CMDLINE_LINUX=\"... cgroup_disable=memory\"\n# after\nGRUB_CMDLINE_LINUX=\"...\"\n# plus enable it for the subtree\necho +memory > /sys/fs/cgroup/neon.slice/cgroup.subtree_control","handlingStrategy":"validation","validationCode":"fn memory_controller_available() -> bool {\n    std::fs::read_to_string(\"/sys/fs/cgroup/cgroup.controllers\")\n        .map(|c| c.split_whitespace().any(|s| s == \"memory\"))\n        .unwrap_or(false)\n}\n\nanyhow::ensure!(memory_controller_available(), \"memory cgroup controller missing; enable it in the parent's cgroup.subtree_control\");","typeGuard":null,"tryCatchPattern":"if let Err(e) = CgroupWatcher::new(name.clone()) {\n    if e.to_string().contains(\"could not find memory subsystem\") {\n        // controller not attached: fix cgroup_disable=memory / subtree_control, then restart\n    }\n    return Err(e);\n}","preventionTips":["Do not boot hosts with cgroup_disable=memory","Delegate the memory controller (Delegate=memory) for containerized vm_monitor","Enable +memory in the parent cgroup's subtree_control in provisioning scripts"],"tags":["linux","cgroups","memory","rust","vm-monitor"],"backgroundTag":"cgroup-controller-missing","analyzedSha":"8f60b04da47ffefe0e52bda2440134b42874eb75","analyzedAt":"2026-08-16T23:39:28.135Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}