nautechsystems/nautilus_trader · error · anyhow::Error
`synthetic` {synthetic.id} already exists
Error message
`synthetic` {synthetic.id} already exists What it means
`DataActor::add_synthetic` checks the cache for an existing instrument with the same `synthetic.id` before adding. Because synthetic IDs are unique keys, adding a duplicate is rejected with this bail instead of silently overwriting the cached instrument.
Source
Thrown at crates/common/src/actor/data_actor.rs:4309
);
let data = CustomData::new(Arc::new(signal), data_type);
let topic = get_custom_topic(&data.data_type);
msgbus::publish_any(topic, &data);
}
/// Adds the `synthetic` instrument to the cache.
///
/// # Errors
///
/// Returns an error if a synthetic with the same ID already exists, or if the
/// backing cache fails to persist it. Panics if the actor is not registered
/// with a trader. // panics-doc-ok
pub fn add_synthetic(&self, synthetic: SyntheticInstrument) -> anyhow::Result<()> {
self.check_registered();
let cache = self.cache_rc();
if cache.borrow().synthetic(&synthetic.id).is_some() {
anyhow::bail!("`synthetic` {} already exists", synthetic.id);
}
cache.borrow_mut().add_synthetic(synthetic)
}
/// Updates the `synthetic` instrument in the cache, replacing the existing entry.
///
/// # Errors
///
/// Returns an error if no synthetic with the same ID already exists, or if the
/// backing cache fails to persist the replacement. Panics if the actor is not
/// registered with a trader. // panics-doc-ok
pub fn update_synthetic(&self, synthetic: SyntheticInstrument) -> anyhow::Result<()> {
self.check_registered();
let cache = self.cache_rc();
if cache.borrow().synthetic(&synthetic.id).is_none() {
anyhow::bail!("`synthetic` {} does not exist", synthetic.id);
}View on GitHub (pinned to 18893faf8b)
Solutions
- Check `cache.synthetic(&id)` (or the actor's existing-synthetic state) before adding and skip if present
- Use `update_synthetic` if the intent is to replace the definition
- Generate a unique ID (e.g. include a run/venue suffix) when creating new synthetics
Example fix
// before
actor.add_synthetic(spread)?;
// after
if actor.cache_rc().borrow().synthetic(&spread.id).is_none() {
actor.add_synthetic(spread)?;
} Defensive patterns
Strategy: validation
Validate before calling
if cache.borrow().synthetic(&id).is_some() { /* skip add or update instead */ } Try / catch
match actor.add_synthetic(synthetic) {
Err(e) if e.to_string().contains("already exists") => { /* already added; reuse existing */ }
other => other?,
} Prevention
- Check cache before adding synthetics
- Generate unique synthetic IDs per run/definition
- Prefer update_synthetic when replacing an existing definition
When it happens
Trigger: Calling `actor.add_synthetic(synthetic)` when `cache.synthetic(&synthetic.id)` already returns Some — i.e. the same synthetic ID was already added (by this actor or another component).
Common situations: Re-running a strategy setup that adds synthetics on each start; constructing a synthetic from config where IDs collide across runs; two actors adding the same synthetic definition.
Understand the failure class
Background: "already exists" / EEXIST / FileAlreadyExistsException: what the 'file already exists' error means and how to fix it — this error's family across 37 libraries.
Related errors
- `synthetic` {synthetic.id} does not exist
- External order claim for {instrument_id} appears more than o
- OrderList denied: duplicate {}
- Order in list denied: duplicate {}
- DataActor {} must be registered before calling `cache()` - t
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/55d08fe0130a494f.
Report an issue: GitHub.