langflow-ai/langflow · error · SystemExit
error: {source} entries field must be a list
Error message
error: {source} entries field must be a list What it means
This error comes from scripts/migrate/check_migration_append_only.py, a CI guard that compares the working-tree migration_table.json against a baseline to enforce that the extension migration table is append-only. After parsing the JSON and confirming the top-level value is an object, it reads data['entries'] and requires it to be a Python list, because each entry maps a legacy component form to its new ext:<bundle> target. If 'entries' is present but not a list (a dict, string, number, or null), the script prints 'error: {source} entries field must be a list' to stderr and exits with code 2 (usage / I/O error).
Source
Thrown at scripts/migrate/check_migration_append_only.py:100
def _parse(raw: str, *, source: str) -> tuple[list[dict], list[dict]]:
"""Return ``(entries, ambiguous_bare_names)`` from a migration-table JSON.
Both lists default to empty when the field is absent so this script can
compare across baselines that pre-date a given field.
"""
try:
data = json.loads(raw)
except json.JSONDecodeError as exc:
print(f"error: invalid JSON in {source}: {exc}", file=sys.stderr)
raise SystemExit(2) from exc
if not isinstance(data, dict):
print(f"error: {source} top-level value must be an object", file=sys.stderr)
raise SystemExit(2)
entries = data.get("entries", [])
if not isinstance(entries, list):
print(f"error: {source} entries field must be a list", file=sys.stderr)
raise SystemExit(2)
ambig = data.get("ambiguous_bare_names", [])
if not isinstance(ambig, list):
print(f"error: {source} ambiguous_bare_names field must be a list", file=sys.stderr)
raise SystemExit(2)
return entries, ambig
def _compare(baseline: list[dict], current: list[dict]) -> list[str]:
"""Return human-readable violations; empty list means clean."""
violations: list[str] = []
current_by_key: dict[tuple[str, str], dict] = {}
for entry in current:
try:
key = _entry_key(entry)
except ValueError as exc:
violations.append(str(exc))
continue
if key in current_by_key:View on GitHub (pinned to 976ec789d2)
Solutions
- Open the file named in the error message and change the 'entries' value to a JSON array of entry objects: "entries": [ { ... }, ... ].
- If you intentionally restructured the table, revert to the documented schema (top-level object with 'entries' list and 'ambiguous_bare_names' list) — the runtime lfx extension migration reader expects exactly that shape.
- If the error names the baseline side, check `git show <base>:src/lfx/src/lfx/extension/migration/migration_table.json | python -m json.tool` to see the malformed value at that ref, or point --baseline at a known-good copy.
- Validate locally before pushing: `python -c "import json;d=json.load(open('src/lfx/src/lfx/extension/migration/migration_table.json'));assert isinstance(d['entries'],list)"`.
Example fix
// before (migration_table.json)
{
"entries": {
"ChatInput": { "target": "ext:helpers:ChatInput" }
},
"ambiguous_bare_names": []
}
// after
{
"entries": [
{ "bare_class_name": "ChatInput", "target": "ext:helpers:ChatInput@official" }
],
"ambiguous_bare_names": []
} Defensive patterns
Strategy: validation
Validate before calling
import json
MANIFEST = "src/lfx/src/lfx/extension/migration/migration_table.json"
def manifest_is_valid(path: str = MANIFEST) -> bool:
data = json.loads(open(path, encoding="utf-8").read())
return (
isinstance(data, dict)
and isinstance(data.get("entries", []), list)
and isinstance(data.get("ambiguous_bare_names", []), list)
)
assert manifest_is_valid(), "run before scripts/migrate/check_migration_append_only.py" Type guard
def is_migration_manifest(data: object) -> bool:
"""Narrow parsed JSON to the migration-table shape."""
if not isinstance(data, dict):
return False
entries = data.get("entries", [])
ambig = data.get("ambiguous_bare_names", [])
return (
isinstance(entries, list)
and all(isinstance(e, dict) for e in entries)
and isinstance(ambig, list)
and all(isinstance(e, dict) for e in ambig)
) Prevention
- Never hand-restructure migration_table.json into keyed objects; the schema is a fixed top-level object with two arrays.
- Add a pre-commit hook that json.loads the table and asserts both fields are lists.
- Treat exit code 2 from check_migration_append_only.py as schema/usage breakage (fix the file), exit code 1 as real append-only violations (fix the diff).
When it happens
Trigger: Running `python scripts/migrate/check_migration_append_only.py` (or with --baseline/--current) where src/lfx/src/lfx/extension/migration/migration_table.json, or the baseline fetched via `git show <base>:src/lfx/src/lfx/extension/migration/migration_table.json`, contains an 'entries' key whose value is not a JSON array — e.g. "entries": {...} or "entries": "none". A missing 'entries' key does NOT trigger it (data.get('entries', []) defaults to []).
Common situations: Hand-editing migration_table.json and accidentally nesting entries under a keyed object (e.g. grouping by provider) instead of an array; a merge conflict resolution that left a stray string; feeding a --baseline file that is actually a different schema (e.g. an export or report) rather than a migration table.
Related errors
- error: {source} ambiguous_bare_names field must be a list
- Invalid flow data
- Invalid JSON format.
- No valid MCP server found in the input.
- error: invalid JSON in {source}: {exc}
AI-assisted analysis of langflow-ai/langflow@976ec789d2 (2026-08-14).
Data as JSON: /api/errors/87055622ed17a923.
Report an issue: GitHub.