{"record":{"id":"b08f68ac60df063e","repo":"nautechsystems/nautilus_trader","slug":"cannot-subscribe-for-externally-aggregated-synthet","errorCode":null,"errorMessage":"Cannot subscribe for externally aggregated synthetic instrument bar data","messagePattern":"Cannot subscribe for externally aggregated synthetic instrument bar data","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/data/src/engine/mod.rs","lineNumber":3243,"sourceCode":"                \"Calling client.execute_subscribe for BookDeltas: {}\",\n                cmd.instrument_id\n            );\n            client.execute_subscribe(client_command);\n        } else {\n            log::error!(\n                \"Cannot handle command: no client found for client_id={:?}, venue={:?}\",\n                cmd.client_id,\n                cmd.venue,\n            );\n        }\n    }\n\n    fn subscribe_bars(&mut self, cmd: &SubscribeBars) -> anyhow::Result<()> {\n        match cmd.bar_type.aggregation_source() {\n            AggregationSource::Internal => self.start_bar_aggregation(cmd)?,\n            AggregationSource::External => {\n                if cmd.bar_type.instrument_id().is_synthetic() {\n                    anyhow::bail!(\n                        \"Cannot subscribe for externally aggregated synthetic instrument bar data\"\n                    );\n                }\n            }\n        }\n\n        Ok(())\n    }\n\n    fn subscribe_synthetic_quotes(&mut self, instrument_id: InstrumentId) {\n        let synthetic = match self.cache.borrow().try_synthetic(&instrument_id).cloned() {\n            Ok(synthetic) => synthetic,\n            Err(e) => {\n                log::error!(\"Cannot subscribe to `QuoteTick` data for synthetic instrument: {e}\");\n                return;\n            }\n        };\n","sourceCodeStart":3225,"sourceCodeEnd":3261,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/data/src/engine/mod.rs#L3225-L3261","documentation":"NautilusTrader's DataEngine only supports synthetic instruments (instrument IDs like 'SYNTH.AAPL-...') when bars are aggregated internally by the engine's own bar aggregators. Subscribing to a synthetic bar type with AggregationSource::External would require the adapter/data source to feed pre-aggregated bars, which cannot exist for a synthetic instrument that no venue provides. The engine therefore rejects the subscription outright.","triggerScenarios":"Calling subscribe_bars (e.g. via strategy.subscribe_bars) with a BarType whose instrument_id is synthetic while the BarType's aggregation source is External — typically a BarType built with an explicit AggregationSource::External argument.","commonSituations":"Constructing BarType.from_str with an aggregation source suffix (e.g. ':external') on a synthetic instrument; copying a subscription snippet meant for real instruments and reusing it for synthetic ones; config files that set aggregation_source=external globally.","solutions":["Remove the External aggregation source so the BarType uses internal aggregation (default); the engine will aggregate the synthetic bar itself via start_bar_aggregation.","If external aggregation is truly needed, use a real (non-synthetic) instrument ID that the data client can provide bars for.","Build the BarType explicitly with AggregationSource::Internal, e.g. BarType::new(instrument_id, spec, AggregationSource::Internal)."],"exampleFix":"// before\nlet bar_type = BarType::new(synthetic_id, bar_spec, AggregationSource::External);\nstrategy.subscribe_bars(bar_type)?;\n// after\nlet bar_type = BarType::new(synthetic_id, bar_spec, AggregationSource::Internal);\nstrategy.subscribe_bars(bar_type)?;","handlingStrategy":"validation","validationCode":"if bar_type.instrument_id().is_synthetic() && bar_type.aggregation_source() == AggregationSource::External {\n    // rebuild with internal aggregation before subscribing\n}\nstrategy.subscribe_bars(BarType::new(bar_type.instrument_id().clone(), bar_type.spec(), AggregationSource::Internal))?;","typeGuard":"fn is_subscribable_synthetic_bar(bt: &BarType) -> bool {\n    !bt.instrument_id().is_synthetic() || bt.aggregation_source() == AggregationSource::Internal\n}","tryCatchPattern":"match strategy.subscribe_bars(bar_type) {\n    Err(e) if e.to_string().contains(\"externally aggregated synthetic\") => {\n        strategy.subscribe_bars(BarType::new(bar_type.instrument_id().clone(), bar_type.spec(), AggregationSource::Internal))?;\n    }\n    r => r?,\n}","preventionTips":["Default to internal aggregation when constructing BarTypes for synthetic instruments","Never append the external aggregation suffix to synthetic instrument bar type strings","Check is_synthetic() on the instrument id before choosing an aggregation source"],"tags":["rust","data-engine","bars","synthetic-instrument"],"backgroundTag":"unsupported-operation","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}