Troubleshooting
Compiling a score, connecting to a model, and hearing audio are separate steps, and each can fail on its own. Find the step that failed from the status or from the operation that rejected, then check the matching section below.
The score does not compile
Read the diagnostic’s line and column. Then check the usual causes: indentation, track names that don’t match a declaration, a missing section length, and the arrangement calls at the bottom. A section that is never called has nothing to play. Diagnostics explains each kind of error and warning.
If you compile with the CLI, a failed compile leaves any earlier output file in place, so an old timeline can still exist.
Shared audio is unavailable
Shared audio depends on the site’s capacity, budget, and session limits, and can be switched off. The dialog says when it is busy or off. Try again later, or choose Your own key. You can keep editing and compiling either way.
Each browser has a daily audio allowance that can be used across sessions. Another session needs at least 30 seconds remaining; when too little is left, the dialog offers tomorrow or your own key. Shared audio also needs one cookie to keep turns fair without an account. If this browser blocks it, allow cookies for this site and reload, or use your own key.
Shared audio only works in this site’s demos. Your own application needs its own key or relay.
There is no sound
play() resolving means generation has started, not that audio is audible yet. Watch the browser host’s audio status: buffering means audio is on its way, and playing means it is reaching the speakers. If the queued audio runs out, the status shows stopped until more arrives, then underrun briefly before it buffers again. Check the device’s output and volume too.
If the status never reaches playing, check the audio context. Browsers only let audio start inside a user gesture, so call createBrowserSession before the click handler’s first await, as Run locally does. If browser.context.state is suspended, the host also reports a context-suspended warning, and the context needs another user gesture to resume.
A key, connection, or provider request failed
A failure arrives as a GasOperationError with a reason:
reason |
What to check |
|---|---|
auth |
The key, and whether its project has access to the model. Retrying the same key won’t help. |
network |
The connection and any relay. Check retryable and closeCode. |
quota |
The provider account’s limits. Retrying straight away can make it worse. |
provider |
The provider’s status and your configuration. Retry only if retryable is true. |
internal |
Your application’s wiring, and the operation in kind. |
The Lyria connector never reports quota: a quota limit closes the connection, so it arrives as network or provider. Connection failures lists how Lyria’s close codes are classified. Codes from 4000 to 4999 come from your own endpoint, such as a relay, so your application decides what they mean.
To recover in a session you keep open, call retryRenderer() before playing again; this needs a connector factory rather than a single connector. Stop your application’s reactions first, and reapply their state after the next play(). The Run locally example takes the simpler route of closing the failed host and creating a new one on the next click.
The model ignored a valid instruction
A score can be valid GAS and still use intent the model doesn’t act on. Read the warnings returned when the score loads, and those on the session’s warning channel. What Lyria supports lists what Lyria ignores or approximates.
Even supported intent is a direction, not a guarantee. A new flavor changes what the model aims for, not any particular note.
A live change is late or partly applied
The model generates ahead, and audio already received plays first, so an accepted change can take a moment to be heard. During playback, a command result’s requestedPosition and appliedPosition show when it was scheduled.
A fragment with a syntax error applies nothing. If a later statement fails, the earlier ones stay applied. Catch rejected calls, and check ok and applied on the result; Live fragments describes the result.
If a change disappears, check whether the run stopped, completed, or retried, because each of these clears overrides. An event in the score can also cover a change you made before pressing Play. Overrides and the cascade explains both. Keep lasting state in your application and reapply it after each play().
Audio continues after leaving the page
Close the browser host on pagehide with browser.close(). It closes the session, the playback, and any audio context it opened; a context you passed in is yours to close. A session that finishes starting after the user has left must be closed too, as Run locally does.
With a finite score, the session can report completion before the last received audio has played. Stopping discards that audio; a natural completion lets it finish.
An import does not resolve
GAS is ESM only. Use a bundler in the browser, and "type": "module" or .mjs files in Node. The umbrella’s root exports the session; everything else has its own subpath, such as @luna-estelar/gas/browser/session.
The individual gas-browser package has no root export, and its older wiring, access, config, playback, and bitsy/* subpaths were removed. Packages and imports lists the current set. Don’t mix the umbrella with other versions of its component packages.