affaan-m/ECC · error · ValueError
config must be a JSON object
Error message
config must be a JSON object
What it means
main() parses the config file (or a loaded application request) and requires the top-level JSON value to be a dict. A JSON array, string, number, or null at the top level raises ValueError('config must be a JSON object').
Solutions
- Wrap the config contents in a top-level JSON object with the expected keys (e.g. integration, inputs)
- Validate the file with python -m json.tool and confirm the outermost value is an object
- Point --config at the correct config file for the chosen --kind
- If using apply-bundle, ensure load_application_request produced a mapping (check the request file format)
Example fix
// before (config.json)
[{"integration": "..."}]
// after
{"integration": "..."} Defensive patterns
Strategy: validation
Validate before calling
import json
config = json.loads(path.read_text())
if not isinstance(config, dict):
raise SystemExit(f'{path}: top-level JSON must be an object') Type guard
def is_json_object(v):
return isinstance(v, dict) Try / catch
try:
config = load_and_check(path)
except ValueError as e:
if 'config must be a JSON object' in str(e):
print(f'Fix {path}: wrap contents in a top-level {{...}} object') Prevention
- Always save configs as objects with named keys, never bare arrays/scalars
- Validate config files with json.tool before submitting them to the CLI
- Use a JSON schema (type: object) in your editor for config files
When it happens
Trigger: The file at args.config contains e.g. a bare JSON array [ ... ] or a quoted string instead of a { ... } object; load_application_request returns a non-dict value.
Common situations: Exporting a list of settings instead of a settings object; saving an empty file or just a scalar; pointing --config at the wrong file (e.g. a workflow JSON that is an array).
Related errors
- local_only must be an exact boolean
- Failed to parse at
- local-only request permits only local_only and integration…
- MCP config must be a JSON object
- A normalized install request is required
AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16).
Data as JSON: /api/errors/4f6c25e6fc3076cd.
Report an issue: GitHub.
Appendix: source
Thrown at skills/taste-application/scripts/workflow_graphs.py:133
graph = json.loads((WORKFLOWS / f'taste-{kind}.json').read_text())
validate_graph(graph)
return graph
def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('--kind', choices=('apply', 'apply-bundle', 'distill'), required=True)
parser.add_argument('--config', type=Path, required=True)
parser.add_argument('--out', type=Path, required=True)
args = parser.parse_args()
try:
if args.kind == 'apply-bundle':
from tasteforge.integration import build_application_bundle, load_application_request
config = load_application_request(args.config)
else:
config = json.loads(args.config.read_text())
if not isinstance(config, dict):
raise ValueError('config must be a JSON object')
local_only = False
if args.kind == 'apply-bundle':
local_only = config.get('local_only', False)
if type(local_only) is not bool:
raise ValueError('local_only must be an exact boolean')
if local_only:
if set(config) != {'local_only', 'integration'}:
raise ValueError('local-only request permits only local_only and integration fields')
payload = build_application_bundle(config['integration'], None, local_only=True)
else:
load_graph('apply' if args.kind == 'apply-bundle' else args.kind)
compile_input = compile_application_input if args.kind != 'distill' else prepare_distillation_input
payload = compile_input(config)
if args.kind == 'apply-bundle':
payload = build_application_bundle(config.get('integration'), payload)
with args.out.open('x') as output:
output.write(json.dumps(payload, indent=2) + '\n')
except (OSError, ValueError, KeyError) as error:View on GitHub (pinned to 8321021c54)