Summary
When a workflow uses swarm.humanAssistance.slack with integrations.relayfile and the active delegated Relayfile credential is read-only (or its write scope has expired), the Slack question write fails with:
[ask-human] Slack human question failed: missing required scope: fs:write
and the runner does not re-mint a write-scoped token. The step hard-fails even though the identity is entitled to fs:write (re-minting joinWorkspace with relayfile:fs:write:/slack/channels/** succeeds when done manually).
Root cause
In @relayflows/core runner.js, askSlackViaRelayfile → askSlackViaRelayfileRuntime only retries after refreshing the token when the error is classified as expired auth:
isRelayfileAuthExpiredError(err) {
const message = err instanceof Error ? err.message : String(err);
return /token has expired|jwt expired|unauthorized|401/i.test(message);
}
A missing required scope: fs:write rejection does not match this pattern, so the for (let attempt = 0; attempt < 2; attempt++) loop rethrows on the first attempt and never calls issueFreshRelayfileRuntimeToken (which would request the slack write fallback scopes and succeed).
Impact
- Any relayflow that posts a Slack human-assistance question fails the moment the local delegated Slack write token lapses (these are short-lived — observed ~24h TTL), with a confusing "missing required scope" error.
agent-relay cloud login does not fix it (that refreshes the CLI token, not the delegated Relayfile write scope), so the failure looks unrecoverable to the user.
Suggested fix
Treat missing required scope (specifically an fs:write scope rejection) as a re-mintable condition: extend isRelayfileAuthExpiredError (or add a sibling isRelayfileScopeError) so the runtime calls issueFreshRelayfileRuntimeToken and retries with the slack write fallback scopes before failing.
Environment
@relayflows/core 1.0.4 (@relayflows/cli 1.0.4), local relayflows run
- Workflow:
swarm.humanAssistance.slack + integrations.relayfile: {}
Summary
When a workflow uses
swarm.humanAssistance.slackwithintegrations.relayfileand the active delegated Relayfile credential is read-only (or its write scope has expired), the Slack question write fails with:and the runner does not re-mint a write-scoped token. The step hard-fails even though the identity is entitled to
fs:write(re-mintingjoinWorkspacewithrelayfile:fs:write:/slack/channels/**succeeds when done manually).Root cause
In
@relayflows/corerunner.js,askSlackViaRelayfile→askSlackViaRelayfileRuntimeonly retries after refreshing the token when the error is classified as expired auth:A
missing required scope: fs:writerejection does not match this pattern, so thefor (let attempt = 0; attempt < 2; attempt++)loop rethrows on the first attempt and never callsissueFreshRelayfileRuntimeToken(which would request the slack write fallback scopes and succeed).Impact
agent-relay cloud logindoes not fix it (that refreshes the CLI token, not the delegated Relayfile write scope), so the failure looks unrecoverable to the user.Suggested fix
Treat
missing required scope(specifically anfs:writescope rejection) as a re-mintable condition: extendisRelayfileAuthExpiredError(or add a siblingisRelayfileScopeError) so the runtime callsissueFreshRelayfileRuntimeTokenand retries with the slack write fallback scopes before failing.Environment
@relayflows/core1.0.4 (@relayflows/cli1.0.4), localrelayflows runswarm.humanAssistance.slack+integrations.relayfile: {}