Skip to content

Salesforce developer known issues

Platform quirks, observed limit-hits, and framework gotchas visible in the current org. For the business-facing view, see docs/human/known-issues.md.

14 SObjects carry more than one Apex trigger. This violates the one-trigger-per-object handler pattern and makes the order of trigger execution implementation-defined.

  • Action: consolidate into a single trigger per object using a handler class. Low-risk objects first.
  • Source: analysis/performance-*.md.

The mix is typically one PWG*Trigger plus one dlrs_*Trigger. If rollup values drift, suspect both frameworks touching the same field.

Workaround: in internal triggers, read the DLRS-rolled value only in after contexts where the managed-package trigger has already fired. Where correctness matters, consider reading from the underlying child records directly.

Out of the historical set, one Workflow Rule remains active. All other automation migrated to Flow. Port or decommission it — it is the only non-Flow automation path left and the easiest to miss when debugging.

80 Flows have five or more versions. Some iteration is normal; five or more suggests an unresolved requirement.

  • Action: spot-audit the top-ten highest-version Flows. Archive older versions to reduce metadata weight.
  • Source: analysis/misconfig-*.md.

Several heavy offenders appear to be “save-as-new-version-instead-of-debug”.

A single integration user (aad.provision@pwg.com.au) regularly holds ~97% of the 24-hour API quota. Confirmed benign — bulk SCIM updates from Entra. But it means headroom is tight; any new chatty integration should be checked against the api-usage report before go-live.

Opportunity → StageName tracking was enabled on 2026-04-24. Any dwell-time analysis over a period pre-dating that has to fall back to CreatedDate + current stage, which is a proxy. When enabling new tracked fields, do it as soon as the use case is known — there is no back-fill.

20-field cap on History Tracking per object

Section titled “20-field cap on History Tracking per object”

A common pitfall. If the Setup page greys out checkboxes, you have hit the cap — remove a low-value field before adding a new one.

23 Apex classes are on API version < 45. These predate several platform features. Nothing is broken, but they drift from current defaults.

  • Action: bump API version alongside any change that touches a legacy class.

These classes predate user-scoped System.runAs behaviour changes, some SOQL feature gates, and newer default security behaviours. Do not bump en masse — old classes may rely on old behaviour.

67 Apex classes exceed 3,000 lines. Most are in FSC or third-party managed packages; custom code is proportionally healthier.

  • Action: when a custom class passes 1,000 lines, split along responsibility boundaries.

Custom-code boundary split: selector, service, handler.

Tooling API EntityDefinition join is fragile

Section titled “Tooling API EntityDefinition join is fragile”

The automation-inventory generator skips the global validation-rules section if the ValidationRuleEntityDefinition join fails — a platform quirk seen intermittently. Per-object validation rules are still captured in docs/generated/objects/*.md.

CORS configuration is not returned by the Tooling API in this org — the generated cors-whitelist.md is empty by design. Use Setup directly.

Not yet captured in docs. Waiting on the metadata_read MCP tool. For now, check Setup → Security → Remote Site Settings.

Connected Apps default to “all users can approve”

Section titled “Connected Apps default to “all users can approve””

44 of 48 Connected Apps allow any authenticated user to authorise them.

  • Impact: a phishing or device-compromise vector — a compromised user can authorise any of these into their session.
  • Action: audit each app, set permittedUsers = admin_approved_users_are_pre_authorized for the ones still in use, revoke the dormant ones.
  • Full list: docs/generated/integrations/connected-apps.md.

Harden with permittedUsers = admin_approved_users_are_pre_authorized and a pre-authorised Permission Set.

Privileged Profile and Permission Set sprawl

Section titled “Privileged Profile and Permission Set sprawl”

11 profiles and 22 Permission Sets grant ModifyAllData, ViewAllData, or admin-like combinations. Not all are in use.

  • Action: audit against analysis/security-*.md and revoke unused privilege.

The aud value in the JWT assertion must exactly match the login URL. Use https://login.salesforce.com or https://test.salesforce.com not the My Domain URL. If the assertion fails with invalid_grant, that is the first thing to check.

jsforce 3.x type definitions are incomplete

Section titled “jsforce 3.x type definitions are incomplete”

The MCP server pins to jsforce 3.x. Several Tooling API return shapes are typed as any. If a field is missing, inspect the raw JSON response rather than relying on the TypeScript type.

  • analysis/performance-*.md — quantified findings
  • analysis/misconfig-*.md — cleanup candidates
  • docs/dev/architecture.md — framework layout this page refers to