GraphiteEditor/Graphite · error

Resource storage not initialized

Error message

Resource storage not initialized

What it means

ResourceStorageMessageHandler wraps an Option<Arc<dyn ResourceStorage>>; resources() clones it with .expect("Resource storage not initialized"). The non-test Default impl deliberately constructs Self { storage: None } (tests get a HashMapResourceStorage instead), so this panic fires exactly when resources() is called on a default-constructed handler - i.e., the editor was wired up without ever providing a resource storage backend. The sibling process_message handles the None case gracefully, so only these accessor call sites panic.

Source

Thrown at editor/src/messages/resource_storage/resource_storage_message_handler.rs:42

	fn garbage_collect(&self, used: &[ResourceHash]) {
		self.inner.garbage_collect(used)
	}
}

#[derive(ExtractField)]
pub struct ResourceStorageMessageHandler {
	storage: Option<Arc<dyn ResourceStorage>>,
}

impl ResourceStorageMessageHandler {
	pub fn new(resource_storage: Arc<dyn ResourceStorage>) -> Self {
		Self { storage: Some(resource_storage) }
	}

	pub fn resources(&self) -> Box<dyn LoadResource> {
		Box::new(ResourcesHandle {
			inner: self.storage.clone().expect("Resource storage not initialized"),
		})
	}

	pub fn resources_mut(&self) -> ResourcesHandle {
		ResourcesHandle {
			inner: self.storage.clone().expect("Resource storage not initialized"),
		}
	}
}

impl std::fmt::Debug for ResourceStorageMessageHandler {
	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
		f.debug_struct("ResourceStorageMessageHandler").finish_non_exhaustive()
	}
}

impl Default for ResourceStorageMessageHandler {
	#[cfg(not(test))]

View on GitHub (pinned to c507b35645)

Solutions

  1. Always construct via ResourceStorageMessageHandler::new(storage) at startup so storage is Some from the beginning
  2. Change resources()/resources_mut() to return Option (or a Result) and let callers skip resource-dependent features when storage is absent
  3. Log loudly at startup when resource storage is not provided so mis-wiring is visible before any panic

Example fix

// before
pub fn resources(&self) -> Box<dyn LoadResource> {
	Box::new(ResourcesHandle { inner: self.storage.clone().expect("Resource storage not initialized") })
}

// after
pub fn resources(&self) -> Option<Box<dyn LoadResource>> {
	self.storage.clone().map(|inner| Box::new(ResourcesHandle { inner }) as Box<dyn LoadResource>)
}
Defensive patterns

Strategy: validation

Validate before calling

if let Some(storage) = &self.storage {
	let handle = ResourcesHandle { inner: storage.clone() };
	// use handle
} else {
	log::error!("resource storage not initialized; skipping resource feature");
}

Type guard

fn is_initialized(handler: &ResourceStorageMessageHandler) -> bool {
	handler.storage.is_some()
}

Prevention

When it happens

Trigger: Constructing the handler via Default::default() (as some generic message-handler scaffolding does) and then calling resources(), which dereferences the never-initialized storage.

Common situations: New entry points (CLI, tests, embedded scenarios) building the editor state with Default instead of ResourceStorageMessageHandler::new(storage); refactors that reset the portfolio/message handlers to defaults at runtime.

Related errors


AI-assisted analysis of GraphiteEditor/Graphite@c507b35645 (2026-08-16). Data as JSON: /api/errors/292d118789a0f451. Report an issue: GitHub.