Skip to content

mattermost: fix DM media upload for unprefixed user IDs#29925

Merged
mukhtharcm merged 4 commits intoopenclaw:mainfrom
teconomix:fix/mattermost-media-dm-channelid
Mar 10, 2026
Merged

mattermost: fix DM media upload for unprefixed user IDs#29925
mukhtharcm merged 4 commits intoopenclaw:mainfrom
teconomix:fix/mattermost-media-dm-channelid

Conversation

@teconomix
Copy link
Copy Markdown
Contributor

Problem

Sending media via the message tool to a Mattermost DM could fail with 403 Forbidden.

Root cause: in Mattermost, user IDs and channel IDs share the same opaque format. The outbound target normalizer treated unprefixed IDs as channel:<id>, causing /api/v4/files uploads to use a user id as channel_id.

Fix

  • Keep unprefixed opaque IDs raw during target normalization so the send path can resolve them with API context.
  • Resolve ambiguous unprefixed IDs user-first in sendMessageMattermost:
    • If GET /api/v4/users/<id> succeeds, resolve the DM channel via POST /api/v4/channels/direct and send there.
    • Otherwise treat the id as a channel id (backward compatible).
  • Add small caches (user-exists + dm channel id).

Docs

Document the new behavior in docs/channels/mattermost.md and update the cron target reminder.

Tests

Added unit tests for normalization + recipient resolution.

Closes #29881.

@openclaw-barnacle openclaw-barnacle bot added docs Improvements or additions to documentation channel: mattermost Channel integration: mattermost size: S labels Feb 28, 2026
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9be1e8bad8

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +222 to +224
} catch {
userIdResolutionCache.set(key, false);
target = { kind: "channel", id: trimmedTo };
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Cache channel fallback only for user-not-found responses

The catch branch treats every fetchMattermostUser failure as “not a user” and permanently caches false, so a transient API/network failure (or a 5xx/429) during one send will poison that recipient for the rest of the process: later sends skip user resolution, are forced down the channel path, and can no longer DM that user by bare ID. This fallback should be limited to confirmed not-found cases and non-404 errors should be surfaced/retried instead of cached as channel.

Useful? React with 👍 / 👎.

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Feb 28, 2026

Greptile Summary

Fixes 403 Forbidden errors when sending media to Mattermost DMs by implementing user-first resolution for unprefixed opaque IDs.

Key changes:

  • Modified normalize.ts to keep unprefixed opaque IDs raw (matching /^[a-z0-9]{8,}$/i) instead of automatically treating them as channel IDs
  • Added user-first resolution in sendMessageMattermost: tries GET /api/v4/users/<id> first, falls back to channel ID if user lookup fails
  • Implements caching for user existence checks and DM channel IDs to optimize performance
  • Only caches negative user resolution for confirmed 404s, avoiding cache poisoning from transient errors (429, 5xx)
  • Updated documentation in mattermost.md and cron-jobs.md to explain the new behavior and recommend explicit prefixes for deterministic behavior
  • Added comprehensive unit tests covering both user and channel resolution paths

Confidence Score: 4/5

  • This PR is safe to merge with minimal risk
  • The implementation is solid with good error handling, comprehensive tests, and clear documentation. The user-first resolution strategy is well-reasoned and maintains backward compatibility. The only minor concerns are around cache management (no TTL) and test coverage for error parsing logic, but these don't affect the core functionality or safety of the changes.
  • No files require special attention

Last reviewed commit: f2d6a9c

@teconomix
Copy link
Copy Markdown
Contributor Author

Thanks for the reviews — I pushed an update that addresses both the CI failure and the caching concern raised by Codex:

  • Fixed pnpm check (tsgo) failures in extensions/mattermost/src/mattermost/send.test.ts (TS2556 spread arg typing).
  • Avoid negative cache poisoning: we now cache isUser=false only for confirmed 404 (user-not-found). For transient/network/5xx/429 errors we do not cache a negative result.

@greptile review

@openclaw-barnacle openclaw-barnacle bot added the gateway Gateway runtime label Feb 28, 2026
@teconomix
Copy link
Copy Markdown
Contributor Author

Update: the remaining CI failure was unrelated to the Mattermost change set.

pnpm check failed due to a TypeScript narrowing issue on runtimeConfig.agents.list items (union included false), in src/gateway/server-cron.ts.

I merged latest origin/main and pushed a small fix that explicitly narrows the agent entry to AgentConfig before accessing .heartbeat.

Local pnpm check now passes.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: fc984eb0b5

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +34 to +35
if (/^[a-z0-9]{8,}$/i.test(trimmed)) {
return trimmed;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Canonicalize opaque IDs before context comparisons

Returning bare opaque IDs here changes the canonical form emitted by normalizeTargetForProvider, so 64if... and channel:64if... are no longer treated as the same destination. When currentChannelId was captured as a raw ID (for example from --to) and a later send uses an explicit prefix, isCrossContextTarget in src/infra/outbound/outbound-policy.ts will misclassify it as cross-context, which can add incorrect cross-context markers or deny the send when allowWithinProvider is disabled. Normalize both forms to a single canonical representation before policy checks.

Useful? React with 👍 / 👎.

@openclaw-barnacle openclaw-barnacle bot removed the gateway Gateway runtime label Mar 1, 2026
@teconomix
Copy link
Copy Markdown
Contributor Author

Addressed both Codex review comments in commit 12e158b.

P1 (cache poisoning on non-404 errors) — already handled in prior commit. The catch branch only caches false when status === 404 (via parseMattermostApiStatus). Transient errors fall through without poisoning the cache.

P2 (canonicalize opaque IDs) — Added a comment in normalize.ts documenting the intentional trade-off: unprefixed opaque IDs must stay raw so isExplicitMattermostTarget in send.ts correctly identifies ambiguity and triggers user-first DM resolution. Normalizing to channel:ID upfront would bypass the user check and break DM delivery. The comment notes callers doing context comparisons should strip the channel: prefix when comparing against bare opaque IDs.

Merge conflict resolvedserver-cron.ts conflict resolved by taking upstream main's cleaner agentEntry/agentHeartbeat pattern.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 12e158bfc9

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

// user-first DM resolution (send.ts) requires the raw form to detect ambiguity.
// If this causes false cross-context mismatches in policy checks, callers should
// strip the "channel:" prefix before comparing against bare opaque IDs.
if (/^[a-z0-9]{8,}$/i.test(trimmed)) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep opaque Mattermost IDs in canonical target form

Returning bare opaque IDs here breaks equality checks that rely on provider normalization for same-target detection. In Mattermost inbound handling, OriginatingTo is always prefixed (for channels: channel:<id>), but extractMessagingToolSend stores bare IDs after normalization and shouldSuppressMessagingToolReplies compares normalized strings with strict equality (targetKey === originTarget in src/auto-reply/reply/reply-payloads.ts). With this change, a send to a bare channel ID is no longer recognized as the same destination as the originating channel, so reply suppression can fail and produce duplicate follow-up replies in the same conversation.

Useful? React with 👍 / 👎.

@teconomix teconomix force-pushed the fix/mattermost-media-dm-channelid branch from 12e158b to 669dd6c Compare March 2, 2026 20:36
@openclaw-barnacle openclaw-barnacle bot added gateway Gateway runtime size: S and removed size: M labels Mar 2, 2026
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 669dd6c229

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

@teconomix
Copy link
Copy Markdown
Contributor Author

CI Failure Analysis

The bun vitest check failure is caused by two pre-existing upstream test flakes, not by changes in this PR:

1. src/security/skill-scanner.test.ts

AssertionError: expected "readFile" to be called 2 times, but got 1 times

Appears to be a timing/caching issue in the skill scanner test — unrelated to Mattermost changes.

2. src/cron/isolated-agent.uses-last-non-empty-agent-text-as.test.ts

AssertionError: expected 'anthropic' to be 'openai'

Model provider mismatch in an isolated-agent cron test — also unrelated to this PR.

Both failures appear in the bun test run for both PRs (#29587 and #29925) with the same errors, confirming they are upstream issues rather than regressions introduced here.

The node-based test runs (checks (node, test, ...)) pass ✅ on both PRs.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 24c7b84f8f

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +14 to +17
on:
push:
branches-ignore:
- main
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Remove fork-only preflight workflow from upstream

This workflow is configured to run on every non-main branch push (on.push.branches-ignore: [main]), so merging it into openclaw/openclaw will add an extra full pnpm check + pnpm build CI run for all branch pushes in the upstream repo. The file itself states it is fork-only and should not be submitted upstream, so keeping it in this commit introduces avoidable CI noise/cost and contradicts its documented scope.

Useful? React with 👍 / 👎.

@teconomix teconomix force-pushed the fix/mattermost-media-dm-channelid branch from 24c7b84 to 46b9c61 Compare March 7, 2026 12:24
@openclaw-barnacle openclaw-barnacle bot added size: S and removed gateway Gateway runtime size: M labels Mar 7, 2026
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 46b9c61712

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".


describe("sendMessageMattermost user-first resolution", () => {
beforeEach(() => {
vi.clearAllMocks();
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Reset send-module caches between user-first tests

This beforeEach only clears mock call state, but send.ts stores userIdResolutionCache and dmChannelCache as module-level Maps that persist across tests; after resolves unprefixed 26-char id as user... runs, FAKE_USER_ID is cached as a user, so the later transient-error case can skip the intended fallback path and fail/order-depend on prior tests instead of validating the cache behavior it claims to test. Reset the module state (or reload the module) for each test in this block.

Useful? React with 👍 / 👎.

@openclaw-barnacle openclaw-barnacle bot added the gateway Gateway runtime label Mar 8, 2026
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8b7c55812d

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +565 to +568
resolvedKind === "user" ||
(resolvedKind !== "channel" &&
resolvedKind !== "group" &&
(lower.startsWith("user:") || trimmed.startsWith("@")));
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve user-prefixed Mattermost targets in session routing

This condition lets resolvedTarget.kind override an explicit user: target, so a send can be routed as a channel even when the normalized destination is a DM. A concrete path is mattermost:<id>: normalizeMattermostMessagingTarget rewrites it to user:<id>, but resolveMessagingTarget can still carry kind: "group"; with this new guard, resolveMattermostSession ignores the user: prefix and builds channel session metadata, which can break DM session continuity and cross-context classification for that send.

Useful? React with 👍 / 👎.

@mukhtharcm mukhtharcm self-assigned this Mar 10, 2026
teconomix and others added 4 commits March 10, 2026 08:27
… uploads

Fixes 403 Forbidden errors when sending media to Mattermost DMs configured
with a bare user ID (e.g. in heartbeat.to or cron targets).

A 26-character alphanumeric Mattermost ID is ambiguous: it could be either a
user ID or a channel ID. Without user-first resolution, bare user IDs are
passed directly to the file upload API as a channel ID, which returns 403.

Changes:
- Probe GET /api/v4/users/<id> before treating a bare 26-char ID as a channel.
  On success, create/reuse a DM channel via POST /channels/direct.
- Cache positive user lookups and DM channel IDs to avoid repeated API calls.
- Cache negative (404) lookups to skip the probe on known channel IDs.
- Transient errors (429, 5xx, network) do NOT poison the cache — the probe
  is retried on the next send.
- Explicit prefixes (user:, channel:, mattermost:, @) bypass the probe.
- DM channel IDs returned by POST /channels/direct are cached per user ID.
- Use strict isMattermostId() (26-char) for the ambiguity guard.

Tests: added user-first resolution suite to send.test.ts covering the DM
path, channel fallback, transient error no-cache behavior, and explicit
prefix bypass.
…ix guidance

- mattermost.md: replace 'Bare IDs are treated as channels' with accurate
  description of user-first resolution behavior.
- cron-jobs.md: add note that bare 26-char Mattermost IDs use user-first
  resolution; recommend explicit prefixes for deterministic routing.
@mukhtharcm mukhtharcm force-pushed the fix/mattermost-media-dm-channelid branch from 8b7c558 to 5cffcb0 Compare March 10, 2026 08:41
@mukhtharcm mukhtharcm merged commit 6d0547d into openclaw:main Mar 10, 2026
28 checks passed
@mukhtharcm
Copy link
Copy Markdown
Member

Merged via squash.

Thanks @teconomix!

mrosmarin added a commit to mrosmarin/openclaw that referenced this pull request Mar 10, 2026
* main: (43 commits)
  docs: add openclaw#42173 to CHANGELOG — strip leaked model control tokens (openclaw#42216)
  Agents: align onPayload callback and OAuth imports
  docs: add Tengji (George) Zhang to maintainer table (openclaw#42190)
  fix: strip leaked model control tokens from user-facing text (openclaw#42173)
  Changelog: add unreleased March 9 entries
  chore: add .dev-state to .gitignore (openclaw#41848)
  fix(agents): avoid duplicate same-provider cooldown probes in fallback runs (openclaw#41711)
  fix(mattermost): preserve markdown formatting and native tables (openclaw#18655)
  feat(acp): add resumeSessionId to sessions_spawn for ACP session resume (openclaw#41847)
  ACPX: bump bundled acpx to 0.1.16 (openclaw#41975)
  mattermost: fix DM media upload for unprefixed user IDs (openclaw#29925)
  fix(msteams): use General channel conversation ID as team key for Bot Framework compatibility (openclaw#41838)
  fix(mattermost): read replyTo param in plugin handleAction send (openclaw#41176)
  fix(sandbox): pass real workspace to sessions_spawn when workspaceAccess is ro (openclaw#40757)
  fix(ui): replace Manual RPC text input with sorted method dropdown (openclaw#14967)
  CI: select Swift 6.2 toolchain for CodeQL (openclaw#41787)
  fix(agents): forward memory flush write path (openclaw#41761)
  fix(telegram): move network fallback to resolver-scoped dispatchers (openclaw#40740)
  fix(security): harden replaceMarkers() to catch space/underscore boundary marker variants (openclaw#35983)
  fix(web-search): recover OpenRouter Perplexity citations from message annotations (openclaw#40881)
  ...
JonathanJing added a commit to JonathanJing/openclaw that referenced this pull request Mar 10, 2026
… creation

Adds exponential backoff retry mechanism for Mattermost DM channel creation
to handle transient failures (429, 5xx, network errors).

Changes:
- Add createMattermostDirectChannelWithRetry() with configurable retry options
- Support maxRetries, initialDelayMs, maxDelayMs, timeoutMs parameters
- Add dmChannelRetry config option to Mattermost account schema
- Allow per-send override via dmRetryOptions in MattermostSendOpts
- Add comprehensive tests for retry logic and error handling
- Retry on: 429 rate limits, 5xx server errors, network/transient errors
- Don't retry on: 4xx client errors (except 429)

Fixes the gap identified in PR openclaw#29925 where initial DM channel creation
failures had no retry mechanism.
Moshiii pushed a commit to Moshiii/openclaw that referenced this pull request Mar 11, 2026
Merged via squash.

Prepared head SHA: 5cffcb0
Co-authored-by: teconomix <[email protected]>
Co-authored-by: mukhtharcm <[email protected]>
Reviewed-by: @mukhtharcm
Moshiii pushed a commit to Moshiii/openclaw that referenced this pull request Mar 11, 2026
Merged via squash.

Prepared head SHA: 5cffcb0
Co-authored-by: teconomix <[email protected]>
Co-authored-by: mukhtharcm <[email protected]>
Reviewed-by: @mukhtharcm
frankekn pushed a commit to MoerAI/openclaw that referenced this pull request Mar 11, 2026
Merged via squash.

Prepared head SHA: 5cffcb0
Co-authored-by: teconomix <[email protected]>
Co-authored-by: mukhtharcm <[email protected]>
Reviewed-by: @mukhtharcm
frankekn pushed a commit to Effet/openclaw that referenced this pull request Mar 11, 2026
Merged via squash.

Prepared head SHA: 5cffcb0
Co-authored-by: teconomix <[email protected]>
Co-authored-by: mukhtharcm <[email protected]>
Reviewed-by: @mukhtharcm
frankekn pushed a commit to ImLukeF/openclaw that referenced this pull request Mar 11, 2026
Merged via squash.

Prepared head SHA: 5cffcb0
Co-authored-by: teconomix <[email protected]>
Co-authored-by: mukhtharcm <[email protected]>
Reviewed-by: @mukhtharcm
dominicnunez pushed a commit to dominicnunez/openclaw that referenced this pull request Mar 11, 2026
Merged via squash.

Prepared head SHA: 5cffcb0
Co-authored-by: teconomix <[email protected]>
Co-authored-by: mukhtharcm <[email protected]>
Reviewed-by: @mukhtharcm
dhoman pushed a commit to dhoman/chrono-claw that referenced this pull request Mar 11, 2026
Merged via squash.

Prepared head SHA: 5cffcb0
Co-authored-by: teconomix <[email protected]>
Co-authored-by: mukhtharcm <[email protected]>
Reviewed-by: @mukhtharcm
ahelpercn pushed a commit to ahelpercn/openclaw that referenced this pull request Mar 12, 2026
Merged via squash.

Prepared head SHA: 5cffcb0
Co-authored-by: teconomix <[email protected]>
Co-authored-by: mukhtharcm <[email protected]>
Reviewed-by: @mukhtharcm
Ruijie-Ysp pushed a commit to Ruijie-Ysp/clawdbot that referenced this pull request Mar 12, 2026
Merged via squash.

Prepared head SHA: 5cffcb0
Co-authored-by: teconomix <[email protected]>
Co-authored-by: mukhtharcm <[email protected]>
Reviewed-by: @mukhtharcm
qipyle pushed a commit to qipyle/openclaw that referenced this pull request Mar 12, 2026
Merged via squash.

Prepared head SHA: 5cffcb0
Co-authored-by: teconomix <[email protected]>
Co-authored-by: mukhtharcm <[email protected]>
Reviewed-by: @mukhtharcm
mukhtharcm pushed a commit to JonathanJing/openclaw that referenced this pull request Mar 17, 2026
… creation

Adds exponential backoff retry mechanism for Mattermost DM channel creation
to handle transient failures (429, 5xx, network errors).

Changes:
- Add createMattermostDirectChannelWithRetry() with configurable retry options
- Support maxRetries, initialDelayMs, maxDelayMs, timeoutMs parameters
- Add dmChannelRetry config option to Mattermost account schema
- Allow per-send override via dmRetryOptions in MattermostSendOpts
- Add comprehensive tests for retry logic and error handling
- Retry on: 429 rate limits, 5xx server errors, network/transient errors
- Don't retry on: 4xx client errors (except 429)

Fixes the gap identified in PR openclaw#29925 where initial DM channel creation
failures had no retry mechanism.
senw-developers pushed a commit to senw-developers/va-openclaw that referenced this pull request Mar 17, 2026
Merged via squash.

Prepared head SHA: 5cffcb0
Co-authored-by: teconomix <[email protected]>
Co-authored-by: mukhtharcm <[email protected]>
Reviewed-by: @mukhtharcm
V-Gutierrez pushed a commit to V-Gutierrez/openclaw-vendor that referenced this pull request Mar 17, 2026
Merged via squash.

Prepared head SHA: 5cffcb0
Co-authored-by: teconomix <[email protected]>
Co-authored-by: mukhtharcm <[email protected]>
Reviewed-by: @mukhtharcm
mukhtharcm pushed a commit to JonathanJing/openclaw that referenced this pull request Mar 17, 2026
… creation

Adds exponential backoff retry mechanism for Mattermost DM channel creation
to handle transient failures (429, 5xx, network errors).

Changes:
- Add createMattermostDirectChannelWithRetry() with configurable retry options
- Support maxRetries, initialDelayMs, maxDelayMs, timeoutMs parameters
- Add dmChannelRetry config option to Mattermost account schema
- Allow per-send override via dmRetryOptions in MattermostSendOpts
- Add comprehensive tests for retry logic and error handling
- Retry on: 429 rate limits, 5xx server errors, network/transient errors
- Don't retry on: 4xx client errors (except 429)

Fixes the gap identified in PR openclaw#29925 where initial DM channel creation
failures had no retry mechanism.
mukhtharcm pushed a commit to JonathanJing/openclaw that referenced this pull request Mar 17, 2026
… creation

Adds exponential backoff retry mechanism for Mattermost DM channel creation
to handle transient failures (429, 5xx, network errors).

Changes:
- Add createMattermostDirectChannelWithRetry() with configurable retry options
- Support maxRetries, initialDelayMs, maxDelayMs, timeoutMs parameters
- Add dmChannelRetry config option to Mattermost account schema
- Allow per-send override via dmRetryOptions in MattermostSendOpts
- Add comprehensive tests for retry logic and error handling
- Retry on: 429 rate limits, 5xx server errors, network/transient errors
- Don't retry on: 4xx client errors (except 429)

Fixes the gap identified in PR openclaw#29925 where initial DM channel creation
failures had no retry mechanism.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

channel: mattermost Channel integration: mattermost docs Improvements or additions to documentation gateway Gateway runtime size: M

Projects

None yet

Development

Successfully merging this pull request may close these issues.

mattermost: message tool media upload fails with 403 in DMs (channel_id not resolved)

2 participants