Simple Object Designer Documentation
Index

Circular Dependencies

Circular dependencies occur when objects reference each other in ways that prevent compilation. This page explains how to identify and resolve them.

What Are Circular Dependencies

The Problem

A circular dependency occurs when:

  • Object A references Object B
  • Object B references Object A
  • Neither can compile without the other

In SOD Context

Common scenarios:

  • Page extension needs table extension fields
  • Table extension references page elements
  • Complex feature interdependencies

Identifying Circular Dependencies

Error Messages

Look for:

  • "Circular dependency detected"
  • "Cannot resolve dependency"
  • Compilation failures mentioning dependencies

Common Patterns

Pattern Description
Table ↔ Page Table and page reference each other
Feature ↔ Extension New feature references extended objects
Multi-object Chain of references creates a cycle
SOD app ↔ Designer personalization app A client-side Designer app took a dependency on the SOD app
Same App ID under two names An already-published app effectively depends on itself

The Designer Personalization App

A CircularDependency deployment failure can arise between a SOD-generated app — typically the second app in Dual-App mode — and a separate extension created by the Business Central Designer (client-side UI personalization).

Why it happens: when a user moves fields in the Designer to sit before or after SOD-generated fields, the personalization app takes a dependency on the SOD app. The error names both apps in the dependency path.

Resolution:

  1. Uninstall the personalization (Designer) app
  2. Refresh Symbols with cache clearing
  3. Retry publishing

Best practice: place SOD-created fields within SOD, not through the Designer, to keep cross-dependencies from forming. Note that on its own this did not prevent the problem in the reported case — the steps above are the fix.

Same App ID Under Two Names

Symptom: deployment fails with Type: CircularDependency, and the dependency path shows two apps that share the same App ID but have different names and different versions. The app depends on itself.

Cause: the Extension Name and/or Start Object Number was changed on a customization that was already published. Reusing the same App ID under a new name, against the app already installed, produces this self-referential dependency.

Prevention: treat changing the Extension Name on a published customization as just as disruptive as changing the Start Object Number. Both require the full procedure described in Object Numbering → "Changing Object Numbers": export the configuration, uninstall the existing extension, delete the existing SOD data, configure the new value, re-create the customizations, and publish again.

The Dual-App Solution

How It Solves the Problem

Dual-App mode:

  1. Splits objects into two apps
  2. App 1 (tables) has no dependencies on App 2
  3. App 2 (pages) depends on App 1
  4. No circular reference possible

When to Use Dual-App

Use when:

  • Single-app compilation fails with circular dependency
  • Complex customizations

Enabling Dual-App

Steps

  1. Open Setup
  2. Set App Mode to Dual
  3. Configure Extension Name 2
  4. Publish

Requirements

  • Two unique extension names
  • Proper deployment order

See Dual-App Overview for details.

Alternative Solutions

Restructure Customizations

Sometimes circular dependencies can be avoided:

  • Rethink the design
  • Remove unnecessary references
  • Simplify relationships

Evaluate Necessity

Ask:

  • Is this reference really needed?
  • Can the design be simplified?
  • Is there an alternative approach?

Prevention

Design Considerations

When planning customizations:

  • Consider dependency direction
  • Keep references one-way when possible
  • Plan for Dual-App if complexity warrants

Incremental Development

Build incrementally:

  • Add objects one at a time
  • Publish frequently
  • Catch issues early

Troubleshooting

If Dual-App Doesn't Help

Check:

  • Are both extension names configured?
  • Is the error actually circular dependency?

Persistent Issues

If problems continue:

  1. Review the specific error
  2. Identify which objects are involved
  3. Consider restructuring
  4. Seek support if needed

How Dependencies End Up in a Generated App

Dependencies are resolved automatically by the compiler — you never add them by hand in SOD. They are written into the generated app's app.json under "dependencies", and Business Central pulls in everything listed there when the app is published.

The most common source of unwanted dependencies

Creating an API or page where all fields on a table are selected. "All fields" can include fields contributed by other installed apps — third-party or ISV extensions — and selecting them makes those apps dependencies of yours.

This is why a generated app can arrive in the target environment demanding an extension you have never deliberately used. See also the note on inherited dependencies in Publishing Failures: if one of your dependencies itself depends on X, you depend on X too.

Dependencies cannot be made individually selectable in SOD (or in Advanced Cloud Security). This was attempted and is not feasible, because there are dependencies between the dependencies.

Removing an unwanted dependency

  1. Identify the API pages or objects that select all fields on a table where those fields include fields belonging to the unwanted app
  2. Remove those fields from the table selection / API page — only do this if your app genuinely does not rely on that app's objects or functionality
  3. Go to Symbols and refresh the symbols list so dependency information is current
  4. Regenerate the extension

Step 3 matters: if symbols are not refreshed, previously deleted ISV apps can still appear as dependencies in the newly generated app.json. You can verify by opening the .app file in VS Code.

The same behaviour and procedure apply to apps generated by Advanced Cloud Security.

Cleaning up already-installed dependency apps

Publishing a corrected app does not always remove dependency apps that are already installed in the environment. Uninstall and unpublish them directly, via Extension Management or PowerShell.

Consuming SOD Fields from an AL Extension

If you write an AL extension that uses fields created in SOD, add the SOD app as a dependency in your app.json. Three rules decide whether it will publish.

1. The dependency version must match exactly. The version in your app.json must match the version of the SOD app actually installed in the target tenant. A mismatch gives:

AL1024: A package with publisher '...', name '...', and a version compatible with '...' could not be loaded.
        Symbols ... could not be found among this tenant's installed apps.
AL0270: The referenced control was not found.

Being able to download symbols in VS Code does not guarantee the installed version matches the one referenced in app.json.

2. A PTE cannot depend on a Dev app. SOD deploys its app as a per-tenant extension. If the app you depend on was published with "Dev" deployment rather than as a PTE, publishing fails with:

AVS0109: The per-tenant extension (or one of its dependencies) cannot be deployed as it has
         missing dependencies or the dependencies are conflicting with currently installed apps.

Confirm the dependency app is deployed as a PTE.

3. The dependency must go one way only. Two extensions cannot depend on each other. A circular dependency between your AL extension and the SOD app fails publishing, and can cause the dependency app to uninstall itself during the attempt.

When republishing the SOD app from within SOD for this purpose, use the Microsoft compiler rather than the legacy compiler.

Error code checklist

Error Cause
AL1024 / AL0270 Dependency version in app.json does not match the installed SOD app version
AVS0109 The dependency app is deployed as a Dev app while yours is a PTE, or a dependency is missing/conflicting
Dependency app uninstalls itself during deploy Version mismatch or a circular dependency between the two extensions

Pageextensions are the mechanism for adding actions — a print action, for example — to SOD-generated pages, and any such AL extension needs the dependency declaration above. See Limitations and Graduating from SOD.

Best Practices

Keep It Simple

  • Avoid unnecessary complexity
  • Use straightforward references
  • Don't over-engineer

Plan Ahead

  • Consider dependencies when designing
  • Test early and often
  • Use Dual-App proactively if needed

Document

  • Note any circular dependency solutions
  • Document why Dual-App was needed
  • Help future maintainers understand