{"record":{"id":"51cc0b13f1cab029","repo":"langflow-ai/langflow","slug":"error-source-ambiguous-bare-names-field-must-be","errorCode":null,"errorMessage":"error: {source} ambiguous_bare_names field must be a list","messagePattern":"error: (.+?) ambiguous_bare_names field must be a list","errorType":"console","errorClass":"SystemExit","httpStatus":null,"severity":"error","filePath":"scripts/migrate/check_migration_append_only.py","lineNumber":104,"sourceCode":"    Both lists default to empty when the field is absent so this script can\n    compare across baselines that pre-date a given field.\n    \"\"\"\n    try:\n        data = json.loads(raw)\n    except json.JSONDecodeError as exc:\n        print(f\"error: invalid JSON in {source}: {exc}\", file=sys.stderr)\n        raise SystemExit(2) from exc\n    if not isinstance(data, dict):\n        print(f\"error: {source} top-level value must be an object\", file=sys.stderr)\n        raise SystemExit(2)\n    entries = data.get(\"entries\", [])\n    if not isinstance(entries, list):\n        print(f\"error: {source} entries field must be a list\", file=sys.stderr)\n        raise SystemExit(2)\n    ambig = data.get(\"ambiguous_bare_names\", [])\n    if not isinstance(ambig, list):\n        print(f\"error: {source} ambiguous_bare_names field must be a list\", file=sys.stderr)\n        raise SystemExit(2)\n    return entries, ambig\n\n\ndef _compare(baseline: list[dict], current: list[dict]) -> list[str]:\n    \"\"\"Return human-readable violations; empty list means clean.\"\"\"\n    violations: list[str] = []\n    current_by_key: dict[tuple[str, str], dict] = {}\n    for entry in current:\n        try:\n            key = _entry_key(entry)\n        except ValueError as exc:\n            violations.append(str(exc))\n            continue\n        if key in current_by_key:\n            violations.append(f\"duplicate entry in current table: {key[0]}={key[1]!r}\")\n            continue\n        current_by_key[key] = entry\n","sourceCodeStart":86,"sourceCodeEnd":122,"githubUrl":"https://github.com/langflow-ai/langflow/blob/976ec789d2886a86de109c044d089d68e96c9a35/scripts/migrate/check_migration_append_only.py#L86-L122","documentation":"Same CI guard script (check_migration_append_only.py): after validating that 'entries' is a list, it validates the companion 'ambiguous_bare_names' field, which records bare component names that map to more than one candidate. This field must also be a JSON list; the append-only invariant says a marker may never be removed and its 'candidates' may only grow, which only makes sense for list data. If the field exists but is not a list, the script prints 'error: {source} ambiguous_bare_names field must be a list' and exits 2.","triggerScenarios":"Running the check against a migration_table.json (current tree via --current default, or a --baseline file, or the git-show baseline) whose top-level 'ambiguous_bare_names' value is an object/string/number/bool. As with 'entries', a missing key defaults to [] and passes.","commonSituations":"Editing the table and converting the ambiguous-name markers into a dict keyed by class name (e.g. {\"Agent\": {...}}) for readability; copy-pasting a config-style object from a doc; schema drift after a tool rewrote the JSON.","solutions":["Change 'ambiguous_bare_names' back to an array of marker objects (each with the bare name and its 'candidates' list).","Check both sides named in the error ({source} tells you whether it is the baseline or the current file) — fix whichever is malformed.","Re-run `python scripts/migrate/check_migration_append_only.py` and confirm exit code 0 or 1 (1 means real append-only violations, not a schema problem)."],"exampleFix":"// before\n\"ambiguous_bare_names\": { \"Agent\": [\"ext:langchain:Agent\", \"ext:crewai:Agent\"] }\n\n// after\n\"ambiguous_bare_names\": [\n  { \"bare_class_name\": \"Agent\", \"candidates\": [\"ext:langchain:Agent\", \"ext:crewai:Agent\"] }\n]","handlingStrategy":"validation","validationCode":"import json\n\ndef ambig_field_ok(path: str) -> bool:\n    data = json.loads(open(path, encoding=\"utf-8\").read())\n    return isinstance(data.get(\"ambiguous_bare_names\", []), list)","typeGuard":"def has_list_ambiguous_names(data: dict) -> bool:\n    ambig = data.get(\"ambiguous_bare_names\", [])\n    return isinstance(ambig, list) and all(isinstance(m, dict) and isinstance(m.get(\"candidates\", []), list) for m in ambig)","tryCatchPattern":null,"preventionTips":["Keep ambiguous-name markers as array elements with a 'candidates' list — never a dict keyed by class name.","Run the append-only check locally (python scripts/migrate/check_migration_append_only.py) before pushing; CI failing on this wastes a cycle.","When resolving merge conflicts in the table, re-emit it via json.dumps to restore canonical shape."],"tags":["json","migration","validation","ci"],"backgroundTag":null,"analyzedSha":"976ec789d2886a86de109c044d089d68e96c9a35","analyzedAt":"2026-08-14T18:23:12.227Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}