Read Every Failure
Requests return a Result to check, and the SDK repeats a write only after a rate limit

Calls Return a Result
A request such as a reply does not throw when Fluxer refuses it or the network drops. It returns a Result, a value that holds either what the request produced or why it failed
Check isErr() first, then read value. A missing permission or a network error arrives as the Result's error, so no try and catch is needed
import { describeError, type Client, type Message } from "@neontechspace/fluxerly"export async function replyHello(client: Client, message: Message) { if (message.author.isBot) return const result = await client.messages.reply(message, `Hello, ${message.author.username}!`) if (result.isErr()) { console.error(describeError(result.error)) return } return result.value }Retry Only When It Is Safe
A send that failed may still have been posted, for example when the answer was lost on its way back. Sending again would reply twice
errors.isRetryable says yes only when repeating the call is safe, such as when the first attempt never left the bot. Any other failure is returned, and the SDK reports it with its message and suggested fix
The SDK keeps the same rule for itself. It sends a write again only after Fluxer asks it to wait for a rate limit, never a write whose outcome is unknown

import { errors, runBot } from "@neontechspace/fluxerly"await runBot({ token: process.env.FLUXER_BOT_TOKEN, events: { messageCreate: async ({ message, reply }) => { if (message.content !== "!ping") return undefined const first = await reply("Pong!") if (first.isOk() || !errors.isRetryable(first.error)) return first await new Promise((resolve) => setTimeout(resolve, errors.retryAfterMs(first.error) ?? 1_000)) return reply("Pong!") }, },})Failures with No Caller Go to onError
A handler that throws or a command that fails has no caller to return to. The SDK sends each one to onError, a hook you pass to runBot, with the original error and the IDs of the message involved, never its content
Without a hook, the SDK logs the failure in full. Reports wait their turn while the hook is busy, and any that cannot wait are logged instead and counted, so none disappear
import { runBot } from "@neontechspace/fluxerly"export function runReportedBot(token: string | undefined, report: (text: string) => void) { return runBot({ token, onError: (failure) => report(failure.describe()), events: { messageCreate: ({ message, reply }) => { if (message.content !== "!ping") return undefined return reply("Pong!") }, }, })}
Errors with a Code and a Hint
Every SDK error has a fixed code, a hint with the next step when there is one, and details that are safe to log. errors.apiCode names Fluxer's own reason, such as missingPermissions
describeError prints all of it with the chain of causes, and masks credentials on the way
import { describeError, errors, type Client, type Message } from "@neontechspace/fluxerly"export async function replyOrExplain(client: Client, message: Message) { const result = await client.messages.reply(message, "Pong!") if (result.isOk()) return result.value const error = result.error console.warn(error.code) // A fixed code, such as message.send.rejected console.warn(error.hint) // The suggested next step, when there is one if (errors.apiCode(error) === "missingPermissions") { console.warn(error.details.requiredPermissions) // Such as ["ViewChannel", "SendMessages"] } console.error(describeError(error)) // All of it, with the chain of causes }What the Log Says
When a handler fails, the log prints one Error record with the event, the IDs of the message and the error. An expected SDK error shows its code, hint and details instead of stack frames
This one is a reply the bot was not allowed to send. The hint names the permissions to grant and where, and no record ever contains the token
ERRORevents[events
The messageCreate handler failed: Message send failed: Fluxer reports that the bot lacks a required permission (MISSING_PERMISSIONS, HTTP 403)
event=messageCreatesubscriptionId=messageCreate#1messageId=1456074443980800006channelId=1456074443980800002guildId=1456074443980800001
MessageError [message
HintThe bot needs View channel and Send messages for this operation. Grant them to the bot's role in the community settings or the channel's permission overrides. Embeds also need Embed links, files need Attach files, and a forward needs View channel in its source channel
Detailsoperation=sendreason=rejectedoutcome=rejectedstatus=403apiError=MISSING_PERMISSIONSrequiredPermissions=["ViewChannel","SendMessages"]















