Salesforce MuleSoft Developer common mistakes
Salesforce MuleSoft Developer · Understand the traps and how to avoid them.
Applies a RAML trait using the `type:` keyword or a resourceType using `is:`, then wonders why the design fails validation or the inherited methods/parameters never appear.
Both keywords attach reusable blocks to a method or resource and look interchangeable in fragments copied from other designs; candidates memorise the block contents but not which keyword consumes them.
What to do instead
Anchor the rule as a pair: resourceTypes and types use type:, traits use is:. Traits inject method/parameter-level content (headers, query parameters, responses); resourceTypes nest a whole resource structure. Validate in API Designer after every edit.
Splits a specification into fragments with `!include` using a path relative to the project root, or creates a DataType fragment file without the `#%RAML 1.0 DataType` header line.
Candidates think of includes like imports in code, and forget that a fragment file must declare its own fragment kind before it can be parsed standalone.
What to do instead
Resolve every !include path relative to the file that contains it, and put the correct first line in each fragment (#%RAML 1.0 DataType, #%RAML 1.0 Trait, #%RAML 1.0 ResourceType, #%RAML 1.0 Library).
Deploys a Mule application to CloudHub with a plain HTTP Listener and expects the rate-limiting and security policies already configured on the API in API Manager to be enforced at runtime.
Candidates assume a policy is bound to the application name or to the spec version in Exchange, so they skip the runtime link and see traffic pass straight through.
What to do instead
Policies attach through API Autodiscovery: register the API instance in API Manager, then add an autodiscovery element to the flow (before any processing) carrying that API instance ID, with valid platform credentials so the runtime can fetch the policy set.
Configures a rate-limiting policy with SLA tiers in API Manager and then tests with plain requests, expecting each caller to get its own limit; every caller is instead throttled into the same bucket.
SLA tiers are keyed by the client application identity, which only exists once the request is identified, so candidates assume tiers are self-applying.
What to do instead
Apply the Client ID Enforcement policy so the runtime resolves the calling application from its client ID and secret; only then are SLA-based tier limits applied per client. Without it, a tiered limit degrades to a single shared limit.
Expects a `flow-ref` to fire the referenced flow and let the calling flow move on immediately, so results of the referenced flow are read before they exist.
The visual arrow suggests dispatch, and candidates carry over the intuition of asynchronous invocations from other integration styles.
What to do instead
flow-ref is a synchronous call: the calling flow blocks and receives the referenced flow's payload and variables on return. For parallel or fire-and-forget work, use an async scope, a VM or JMS publish, or a scatter-gather route instead.
Uses a scatter-gather expecting a single merged object back, or expecting the caller to be able to proceed as soon as the fastest route returns.
The component name and the visual layout suggest a fan-out that aggregates results into one payload, so the returned array of per-route results is misread.
What to do instead
Remember scatter-gather waits for every route to finish and returns an array of results in route declaration order (result[0] is the first route). Combine or transform that array afterwards with DataWeave if a single object is needed.
Writes `payload map ($.name)` when the payload is a JSON object and hits a runtime error about expecting an Array but receiving an Object.
map reads as a general-purpose "iterate everything" operator, and JSON sample payloads in practice are often arrays, so the habit forms before an object-shaped response is ever tested.
What to do instead
Match the operator to the shape: map for arrays, mapObject for objects (where $$ is the key), pluck when an object must become an array, and filterObject versus filter for the respective shapes. Check the incoming structure before choosing.
Uses `$$` inside a `map` to mean the current element and gets indices (or keys) in the output instead of values.
The two dollar signs are visually near-identical and both are used without a named parameter, so muscle memory picks one and the mistake only surfaces in the rendered output.
What to do instead
Fix the meaning pair: $ is the current value, $$ is the index (for arrays) or key (for objects). For anything non-trivial, name the parameters explicitly, e.g. payload map (item, index) -> ..., so the role of each is visible.
Places an on-error-continue in an inner scope, then expects it to also catch an error raised later in the parent flow or in a sibling flow of the same application.
Candidates treat error handlers as global try/catch around the whole application rather than as handlers owned by a specific scope.
What to do instead
Scope the handler to the level that owns every component it must protect, or wrap the risky components in a try scope with its own error handler. For reuse, define a global error handler and attach it explicitly with error-handler-ref on the flows that need it.
Uses on-error-propagate to signal failure and expects every side effect of the flow, including already-issued HTTP requests and one-way sends, to be undone.
propagate sounds like "roll back everything", blurring the difference between raising an error and reverting a transactional resource.
What to do instead
Rollback only applies inside a transactional scope and only to transactional resources; outbound HTTP calls and already-published messages are not reverted. Keep side-effecting operations late in the flow or behind a transactional scope, and use compensating logic where a true undo is required.