nathanmarz/storm · error · IllegalArgumentException
No output fields defined for component:stream
Error message
No output fields defined for component:stream ${componentId}:${streamId} What it means
GeneralTopologyContext.getComponentOutputFields looks up the declared output Fields for a component/stream pair in the topology definition. If the map has no entry for that (componentId, streamId), it throws this IllegalArgumentException. It means the code asked for output fields of a stream the component never declared, or the stream id is misspelled (including the default stream).
Solutions
- Declare the stream explicitly in declareOutputFields via OutputFieldsDeclarer.declareStream(streamId, fields) before emitting on it
- Verify the exact stream id string matches (including "default") between producer declaration and the getComponentOutputFields call
- Check the componentId matches the name given when setBolt/setSpout in the TopologyBuilder
- If relying on default stream, use declarer.declare(fields) rather than mixing named and default streams
Example fix
// before
// bolt never declares the stream "metrics"
_collector.emit("metrics", tuple, values);
// after
public void declareOutputFields(OutputFieldsDeclarer declarer) {
declarer.declareStream("metrics", new Fields("name", "value"));
} Defensive patterns
Strategy: validation
Validate before calling
// before emitting/consuming a named stream, ensure it is declared:
Topologies topo = ...; // your built topology
Fields f = topo.getBolt("mybolt").getDeclaredFields("metrics"); // or inspect the declared component config
// or in the bolt itself: always declare before use
// declarer.declareStream("metrics", new Fields("name","value")); Try / catch
try {
Fields fields = context.getComponentOutputFields(componentId, streamId);
...
} catch (IllegalArgumentException e) {
LOG.error("Undeclared stream {}:{} for component", streamId, componentId, e);
throw e; // fail fast; declaration bug must be fixed
} Prevention
- Declare every custom stream in declareOutputFields before emitting on it
- Centralize stream id constants instead of string literals
- Verify component names match TopologyBuilder.setBolt/setSpout names exactly
- Smoke-test the full topology wiring in LocalCluster before deploying
When it happens
Trigger: Calling getComponentOutputFields(componentId, streamId) for a component that exists but declared no fields on that stream; using a stream name not passed to declareStream in the bolt/spout's declareOutputFields; wrong default stream id when component only declares named streams; looking up a component that isn't part of the topology.
Common situations: Typos in stream ids between declareStream/emit(streamId,...) and consumer lookups; a bolt emitting to a custom stream the consumer queries under the default "default" id; topology rebalancing/version mismatch where the running topology differs from expected; programmatic topology wiring using wrong component name.
Understand the failure class
Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.
Related errors
- A single worker should have 1 SystemBolt instance.
- Non-system tuples should never be sent to __system bolt.
- Fields for already set
- Bolt has already been declared for id
- Spout has already been declared for id
AI-assisted analysis of nathanmarz/storm@cdb116e942 (2026-09-12).
Data as JSON: /api/errors/42b84fbce1f54af5.
Report an issue: GitHub.
Appendix: source
Thrown at storm-core/src/jvm/backtype/storm/task/GeneralTopologyContext.java:113
}
/**
* Gets the task ids allocated for the given component id. The task ids are
* always returned in ascending order.
*/
public List<Integer> getComponentTasks(String componentId) {
List<Integer> ret = _componentToTasks.get(componentId);
if(ret==null) return new ArrayList<Integer>();
else return new ArrayList<Integer>(ret);
}
/**
* Gets the declared output fields for the specified component/stream.
*/
public Fields getComponentOutputFields(String componentId, String streamId) {
Fields ret = _componentToStreamToFields.get(componentId).get(streamId);
if(ret==null) {
throw new IllegalArgumentException("No output fields defined for component:stream " + componentId + ":" + streamId);
}
return ret;
}
/**
* Gets the declared output fields for the specified global stream id.
*/
public Fields getComponentOutputFields(GlobalStreamId id) {
return getComponentOutputFields(id.get_componentId(), id.get_streamId());
}
/**
* Gets the declared inputs to the specified component.
*
* @return A map from subscribed component/stream to the grouping subscribed with.
*/
public Map<GlobalStreamId, Grouping> getSources(String componentId) {
return getComponentCommon(componentId).get_inputs();View on GitHub (pinned to cdb116e942)