100 Ways to Break a Canvas App on Purpose (So You Learn Faster) - Part 2
-
Admin Content
-
Jul 23, 2025
-
14
Collections, Navigation Nightmares, UX Mayhem & Security Slip-ups
Intro: If you’re reading this, congratulations: you’ve survived 50 intentional disasters and now possess stronger Patch() instincts, cleaner variable usage, and probably a bit of emotional scarring. Now, let’s finish the job. Part 2 dives into everything from Collection chaos and Navigation drama to UX disasters , Security nightmares , and the sweet self-sabotage of app dev culture.
🧺 Section 6: Collection Carnage – Where Temp Data Goes to Die
- Collecting From Multiple Screens Without Sync Breaks when: You use the same collection from different screens assuming it auto-syncs. Fix it like a boss: Use ClearCollect() at App start or when switching screens.
- No ClearCollect() Before Re-collecting Breaks when: You collect repeatedly without clearing — enjoy your duplicates. Fix it: Always use ClearCollect() instead of Collect() for refreshable data.
- Assuming Collections Persist After Close Breaks when: You expect a collection to still be there after the app reloads. Fix it: Use SaveData() and LoadData() for offline persistence.
- Collecting Nested Tables Into a Flat List Breaks when: You try to Collect() a field with nested records. Fix it: Use ForAll() and AddColumns() to flatten nested data before collecting.
- Column Name Collisions Breaks when: Multiple data sources share column names and overwrite in a Collect(). Fix it: Rename columns explicitly using RenameColumns() before merging.
- Overcollecting Instead of Direct Binding Breaks when: You collect the entire data source when binding directly would suffice. Fix it: Bind controls to direct data where possible, especially for small sets.
- Missing Fields in Collection Records Breaks when: You Collect() only partial fields and later Patch() them. Fix it: Ensure full schema consistency using ShowColumns() or mapped schema.
- One-Row-at-a-Time ForAll() + Collect() Breaks when: You loop through 1000 records to collect them individually. Fix it: Use bulk ClearCollect() or server-side logic instead.
- Not De-duplicating Before Display Breaks when: You show users a gallery with repeated rows. Fix it: Wrap collections in Distinct() or build deduplication into Collect() logic.
- Forgetting to RemoveIf() Old Staged Data Breaks when: You don’t clean up staging collections before saves. Fix it: RemoveIf() records with an identifier or flag before saving.
🧭 Section 7: Navigation Nightmares – Getting Lost in Your Own App
- Navigating to Non-Existent Screens Breaks when: You delete a screen and forget it’s still referenced. Fix it like a boss: Use App Checker to clean up orphaned references.
- Context Variables That Don’t Travel Breaks when: You set context on one screen and expect it to be available globally. Fix it: Pass data via Navigate(Screen, {}, {contextVar: value}).
- Stale Form Data Across Screens Breaks when: You don’t reset forms when moving screens. Fix it: Use ResetForm() in the OnVisible or OnSelect logic.
- Using Back() Instead of Navigate() Breaks when: You assume Back() returns to a specific screen — it doesn’t. Fix it: Use Navigate() for precision and Back() only when flow is linear.
- OnVisible Triggers with Redirect Logic Breaks when: You navigate to a screen, and it instantly redirects somewhere else. Fix it: Add flags to control when navigation triggers.
- ConfirmExit Confusion Breaks when: You enable ConfirmExit but don’t account for form state. Fix it: Use Unsaved flags with meaningful messages.
- Looped Navigation Calls Breaks when: You conditionally navigate inside a loop or triggered update. Fix it: Add debounce logic or user-initiated triggers for navigation.
- Missing Context on Deep Links Breaks when: A deep link opens your app but misses required screen context. Fix it: Use Param() with defensive fallbacks.
- Confusing Launch() vs. Navigate() Breaks when: You think Launch() goes to another screen — it launches URLs! Fix it: Reserve Launch() for external links only.
- Not Resetting Modal States Breaks when: You open modals via Visible and forget to reset their flags. Fix it: Always reset varShowModal or equivalent in OnHidden logic.
😵 Section 8: UX Missteps – How to Confuse Users Instantly
- Controls Bound Before Data Loads Breaks when: A dropdown tries to show colOptions before it’s populated. Fix it like a boss: Use loading indicators or disable controls until !IsEmpty().
- Perma-Spinners Breaks when: You set LoadingSpinner = true but forget to turn it off. Fix it: Use Concurrent() or Timer logic to control spinner visibility.
- Control Names Like TextInput23 Breaks when: You have no idea what Dropdown5 is anymore. Fix it: Rename everything meaningfully. You’ll thank yourself later.
- Unhandled Errors Explode on Screen Breaks when: Power Apps shows raw error messages. Fix it: Wrap calls in IfError() and use user-friendly messages.
- No Submit Button Disabled State Breaks when: Users can submit a blank form 20 times. Fix it: Use DisplayMode = If(Form.Valid, DisplayMode.Edit, DisplayMode.Disabled).
- Overstuffed Screens with 30+ Controls Breaks when: App performance tanks and layout goes bonkers. Fix it: Break UI into multiple screens or tabbed containers.
- Accessibility? What Accessibility? Breaks when: Your app can’t be used with a keyboard or screen reader. Fix it: Set TabIndex and Labels for accessibility compliance.
- Color-Coding Logic Backwards Breaks when: You show errors in green and success in red. Fix it: Follow standard color conventions — your users will panic less.
- Popups Without Dismiss Logic Breaks when: Users get stuck in a modal and can’t get out. Fix it: Provide close buttons or Esc key logic.
- Text That Doesn’t Wrap or Scale Breaks when: Your tooltips or labels get cut off. Fix it: Use AutoHeight, wrap text settings, and responsive layouts.
🔐 Section 9: Security Sinkholes – The Data Exposé
- Everyone Gets Edit Access Breaks when: Every user can change every record. Fix it like a boss: Set SharePoint list permissions or use Dataverse roles.
- Using Hidden Controls for Security Breaks when: You hide a button and call it “secure.” Fix it: Never rely on visibility to secure actions. Use server-side rules.
- Local Collection Role Checks Breaks when: You store user roles in a collection that anyone can edit. Fix it: Fetch roles from a secure source at runtime.
- Client-Side Filtering of Secure Data Breaks when: All data is downloaded, and the client filters out what they shouldn't see. Fix it: Apply row-level security at the source.
- Assuming Power Apps = SharePoint Permissions Breaks when: Users can access lists you thought were hidden. Fix it: Configure both app logic and backend list permissions.
- Hardcoding Email Checks Breaks when: You write If(User().Email = "bob@company.com", ...). Fix it: Use role lists or lookup tables, not hardcoded logic.
- Environment Variables Left Wide Open Breaks when: All users can see or modify your environment values. Fix it: Restrict who can manage these via solution security roles.
- Publishing to Everyone Breaks when: You hit “Share with Organization” without testing roles. Fix it: Test with dummy users before org-wide release.
- Saving Secrets in Collections Breaks when: Passwords or API keys are in app variables. Fix it: Use Azure Key Vault or environment secrets via Power Automate.
- Delegation Holes in Security Filters Breaks when: Your Filter(Data, User().Email = Author.Email) isn’t delegable. Fix it: Use server-side filters and indexed columns, or pass permissions via Flow.
🧠 Section 10: Bonus Round – Meta-Mistakes and Developer Self-Sabotage
- No Comments in Formulas Breaks when: You revisit a formula three months later and have no clue what it does. Fix it like a boss: Use /* comments */ in formulas, or separate logic blocks.
- Skipping App.OnStart Logic Breaks when: Your app loads without initializing anything. Fix it: Set up collections, context, and lookups in App.OnStart.
- Screens Named Screen1, Screen2 Breaks when: You lose track of your app's flow. Fix it: Use descriptive names like scrHome, scrAdmin, scrSettings.
- Putting Everything on One Screen Breaks when: Performance dies and UX confuses users. Fix it: Split logic into screens or tabs. Don’t fear modular design.
- Avoiding Components Out of Fear Breaks when: You repeat the same control 8 times instead of reusing a component. Fix it: Build and reuse custom components for maintainability.
- No Versioning Strategy Breaks when: You push updates directly to prod without backup. Fix it: Save app versions and use separate dev/test/prod environments.
- Duplicating Formulas Across Screens Breaks when: You fix a bug once, and forget 5 other places. Fix it: Centralize logic in variables, components, or functions.
- Ignoring Errors Until It’s Too Late Breaks when: Users experience failures you didn’t test for. Fix it: Use Monitor, IfError(), and testing accounts.
- Testing as Yourself Only Breaks when: You test only under your full-permission dev account. Fix it: Use test users with different roles to simulate real behavior.
- Never Using Monitor Breaks when: You spend hours debugging without tools. Fix it: Open the Monitor pane and never look back.
Source: 100 Ways to Break a Canvas App on Purpose (So You Learn Faster) - Part 2