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

  1. Declare the stream explicitly in declareOutputFields via OutputFieldsDeclarer.declareStream(streamId, fields) before emitting on it
  2. Verify the exact stream id string matches (including "default") between producer declaration and the getComponentOutputFields call
  3. Check the componentId matches the name given when setBolt/setSpout in the TopologyBuilder
  4. 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

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


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)