iflytek/astron-agent · error · DOMException
NotSupportedError
NotSupportedError
Error message
The adapter.js addTrack polyfill only supports a single stream which is associated with the specified track.
What it means
The adapter.js addTrack polyfill predates multi-stream track association: it requires exactly one stream argument (r.length === 1) and that the given track actually belongs to that stream (r[0].getTracks().find(e => e === t)). If addTrack is called with zero arguments, multiple streams, or a stream that does not contain the track, it throws DOMException(..., 'NotSupportedError') because the polyfill cannot represent that case.
Solutions
- Always pass exactly one MediaStream that actually contains the track: pc.addTrack(track, streamContainingTrack).
- Upgrade the browser or the avatar SDK/adapter.js bundle so the native addTrack (no polyfill) is used.
- If the track is not in the stream, add it first (stream.addTrack(track)) before calling addTrack, or pass the stream the track actually came from.
- Avoid cloning/re-wrapping tracks between streams before publishing.
Example fix
// before pc.addTrack(audioTrack); // no stream -> NotSupportedError in polyfill // after const outStream = new MediaStream([audioTrack]); pc.addTrack(audioTrack, outStream);
Defensive patterns
Strategy: validation
Validate before calling
function canAddTrack(pc, track, stream) {
return stream && stream.getTracks().includes(track) && pc.signalingState !== 'closed';
} Try / catch
try { pc.addTrack(track, stream); } catch (e) {
if (e.name === 'NotSupportedError' && /addTrack polyfill/.test(e.message)) {
stream.addTrack(track);
pc.addTrack(track, stream);
} else throw e;
} Prevention
- Always supply exactly one stream argument containing the track
- Do not pass cloned/re-wrapped streams whose track identity differs
- Target browsers with native addTrack, or keep adapter.js current in the SDK bundle
- Add a smoke test that publishes audio on the oldest supported browser
When it happens
Trigger: Calling pc.addTrack(track) with no stream; pc.addTrack(track, streamA, streamB) with more than one stream; or pc.addTrack(track, streamB) where track came from a different MediaStream (common when tracks are re-wrapped, cloned, or re-muxed by the SDK).
Common situations: Modern code written against the spec's optional stream argument running on an old browser where adapter.js polyfills addTrack; passing a newly constructed MediaStream that only wraps the track by reference in a different browser context; SDK versions that hand the player re-wrapped streams.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
AI-assisted analysis of iflytek/astron-agent@5e758547a8 (2026-09-12).
Data as JSON: /api/errors/841523c4a72002ae.
Report an issue: GitHub.
Appendix: source
Thrown at console/frontend/src/utils/avatar-sdk-web_3.1.2.1002/xrtc-player-BJTnVhG9.js:19408
}
((e.RTCPeerConnection.prototype.removeStream = function (e) {
((this._streams = this._streams || {}),
(this._reverseStreams = this._reverseStreams || {}),
n.apply(this, [this._streams[e.id] || e]),
delete this._reverseStreams[
this._streams[e.id] ? this._streams[e.id].id : e.id
],
delete this._streams[e.id]);
}),
(e.RTCPeerConnection.prototype.addTrack = function (t, i) {
if ('closed' === this.signalingState)
throw new DOMException(
"The RTCPeerConnection's signalingState is 'closed'.",
'InvalidStateError'
);
const r = [].slice.call(arguments, 1);
if (1 !== r.length || !r[0].getTracks().find(e => e === t))
throw new DOMException(
'The adapter.js addTrack polyfill only supports a single stream which is associated with the specified track.',
'NotSupportedError'
);
const n = this.getSenders().find(e => e.track === t);
if (n)
throw new DOMException('Track already exists.', 'InvalidAccessError');
((this._streams = this._streams || {}),
(this._reverseStreams = this._reverseStreams || {}));
const o = this._streams[i.id];
if (o)
(o.addTrack(t),
Promise.resolve().then(() => {
this.dispatchEvent(new Event('negotiationneeded'));
}));
else {
const r = new e.MediaStream([t]);
((this._streams[i.id] = r),
(this._reverseStreams[r.id] = i),View on GitHub (pinned to 5e758547a8)