Common Issues When Working With Cordis: A Developer’s Guide to Entry Resolution, Configuration, and Runtime Errors

The most frequent errors when developing with Cordis involve entry resolution failures in the hierarchical tree, configuration file handling mishaps, service isolation mismatches, and HMR limitations, all of which stem from specific architectural constraints in the loader and core packages.

Cordis is a meta-framework enabling spatiotemporal composability through a tree of entries and a flexible loader system within the cordiverse/cordis repository. While its architecture provides powerful plugin isolation and hot-reloading capabilities, developers frequently encounter recurring issues ranging from "cannot resolve entry" crashes to silent configuration failures. Understanding the root causes in the source code—particularly within packages/loader/src/config/tree.ts and related modules—allows you to diagnose and prevent these problems systematically.

Entry Resolution and Hierarchy Errors

The entry tree represents plugins as nodes in a colon-separated hierarchy (EntryTree.sep = ':'). When this structure is traversed incorrectly, the framework throws specific resolution errors.

"Cannot Resolve Entry" Errors

When EntryTree.resolve walks an ID path and encounters a missing intermediate node, it throws new Error(\cannot resolve entry ${id}`)` at packages/loader/src/config/tree.ts lines 75-84. This occurs when:

  • An entry ID is malformed or uses incorrect separator syntax
  • The parent group was removed but child references remain
  • The entry was never created during initialization

To diagnose, examine the stack trace for EntryTree.resolve or EntryTree.resolveGroup. Verify that the parent group exists and that you are using the correct hierarchical ID format (parent:child).

"Entry Is Not a Group" Errors

After resolving the parent entry, EntryTree.resolveGroup expects the entry to possess a subgroup property. If absent, it throws new Error(\entry ${id} is not a group`)` at tree.ts lines 88-92. This typically happens when you attempt to treat a leaf plugin as a container for sub-plugins.

Ensure the target entry’s group flag is set to true in its configuration, or verify you are addressing the proper container entry rather than a leaf node.

Disabled Entry Disposal Not Propagated

When an entry is disabled, the loader marks it and disposes its fiber via entry.fiber?.dispose(). However, if the entry’s parent.tree.store still holds a reference, further updates may be silently ignored or cause stale state issues.

After disabling an entry, explicitly remove it from its parent group using group.remove(entry.id) or trigger a tree refresh to ensure proper cleanup.

Configuration File Handling Issues

The loader reads configuration files lazily, which creates specific failure modes when files are missing or permissions are restricted.

Config File Not Found

When a file cannot be opened, the loader propagates ConfigFileError with the message new Error(\config file not found: ${this.filename}`)` at packages/loader/src/index.ts lines 140-142. This is common when the config path is wrong, the file is deleted, or the process lacks read permissions.

Check the loader’s configuration path via ctx.loader.config.baseUrl and confirm the file exists on disk before initialization.

Read-Only Configuration Warnings

When a configuration file is opened in read-only mode, the loader emits this.ctx.logger.warn('config file %C is read-only …') at index.ts lines 326-327. This warning signals that runtime changes will remain in memory only and will not persist to disk.

Verify the file’s POSIX permissions or check if the loader was instantiated with the readOnly flag set to true.

Runtime Patching and Service Isolation

Cordis uses runtime patches to modify configuration entries and isolation realms to separate service instances. Misconfigurations in these areas generate warnings rather than crashes, making them easy to overlook.

Patch Application Failures

The include package applies runtime patches via applyPatches. If a patch target is missing, has a name mismatch, or attempts to insert into a non-group entry, the routine emits warn('patch insert: entry %C not found', id) at packages/include/src/patch.ts lines 70-74.

Inspect the patches array passed to the loader. Ensure each patch’s id matches an existing entry and that insert operations target only groups, not leaf entries.

Service Isolation Mismatches

The isolate plugin creates per-entry or global realms. When a required service is not implemented, it logs entry.ctx.logger.warn(new Error(\expected service ${name} to be implemented`))at **packages/loader/src/config/isolate.ts** lines 110-112. This typically occurs when a plugin depends on a service that was never registered viactx.provide`.

Review the isolate map in the entry’s options and confirm that the dependent service is properly registered in the context before plugin initialization.

Development Environment and Metadata Issues

Specific errors emerge during development related to hot module replacement and test infrastructure leaking into production.

HMR Disabled Warnings

The hmr package warns when internal loader APIs are unavailable: this.ctx.logger.warn('loader internals are unavailable, source code HMR is disabled …') at packages/hmr/src/index.ts lines 141-143. This occurs in environments without the node-addon-require-builtin package or when the --expose-internals flag is omitted.

Enable HMR by passing the necessary CLI flags or installing the required addon to support hot-reloading during development.

Test Error Leaks and Malformed Metadata

Many test suites deliberately throw new Error('boom') or new Error('test') to verify error handling paths, such as in loader/tests/index.spec.ts line 165 and timer/tests/index.spec.ts lines 133-194. If these errors surface in production, they indicate that test code paths were inadvertently shipped.

Additionally, the loader’s built-in plugins are populated from package.json metadata. If the main field is absent or malformed, imports fail with "cannot resolve entry" errors. Verify the package.json in each plugin package points to a valid module.

Defensive Coding Patterns

Implement these patterns to avoid the issues above:

Validate entry IDs using EntryTree.ensureId to guarantee uniqueness and correct colon-separated formatting.

Guard config access by wrapping loader configuration reads in try/catch blocks:

import { readFile } from 'node:fs/promises';

async function loadConfig(loader, filename) {
  try {
    const text = await readFile(filename, 'utf8');
    return JSON.parse(text);
  } catch (e) {
    loader.ctx.logger.warn(`config file ${filename} not found, using defaults`);
    return {};
  }
}

Check service availability before accessing isolated services:

function getRealm(entry, name) {
  const symbol = entry.options.isolate?.[name];
  if (!symbol) return null;
  
  const impl = entry.ctx.reflect.store[symbol];
  if (!impl) {
    entry.ctx.logger.warn(`expected service ${name} to be implemented`);
    return null;
  }
  return symbol;
}

Apply patches safely by passing a custom logger to capture warnings:

import { applyPatches } from '@cordisjs/plugin-include';

function safePatch(data, patches, logger) {
  const warn = (msg: string, ...args: any[]) => logger.warn(msg, ...args);
  return applyPatches(data, patches, warn);
}

Enable HMR in development by spawning Node.js with the required flag:

import { spawn } from 'node:child_process';

spawn('node', ['--expose-internals', 'dev.js'], { stdio: 'inherit' });

Summary

  • Validate entry IDs using EntryTree.ensureId before attempting resolution to prevent "cannot resolve entry" errors.
  • Check group status via the subgroup property before treating entries as containers for sub-plugins.
  • Wrap configuration reads in try/catch blocks to handle ConfigFileError gracefully when files are missing or read-only.
  • Verify patch targets exist and are groups before applying runtime patches via applyPatches.
  • Confirm service registration through ctx.reflect.store before accessing isolated services to avoid implementation warnings.
  • Enable development flags (--expose-internals) and install node-addon-require-builtin to support HMR functionality.

Frequently Asked Questions

Why do I get "cannot resolve entry" errors in Cordis?

This error originates in EntryTree.resolve at packages/loader/src/config/tree.ts lines 75-84 when the colon-separated ID path contains a missing intermediate node. Verify that parent groups exist before referencing child entries and ensure you are using the correct hierarchical syntax (parent:child) rather than flat identifiers.

How do I fix "entry is not a group" errors?

This occurs in EntryTree.resolveGroup at tree.ts lines 88-92 when code attempts to access subgroup on a leaf entry. Set group: true in the entry’s configuration to designate it as a container, or redirect your operation to the correct parent group that holds the target entry.

Why is HMR disabled in my Cordis development environment?

The HMR package checks for internal loader APIs at packages/hmr/src/index.ts lines 141-143. If the node-addon-require-builtin package is missing or Node.js was not started with --expose-internals, hot reloading is disabled. Install the addon or launch your process with the required flag to enable source code HMR.

What causes "expected service to be implemented" warnings?

This warning emits from packages/loader/src/config/isolate.ts lines 110-112 when a plugin’s isolation realm depends on a service not registered via ctx.provide. Ensure all required services are implemented in the context before the plugin initializes, or adjust the isolate configuration to remove dependencies on unavailable services.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →