affaan-m/ECC · error · ValueError
local_only must be an exact boolean
Error message
local_only must be an exact boolean
What it means
For apply-bundle configs, the optional local_only field must be a real JSON boolean (type is bool, so 1/0 or "true" strings are rejected). main() raises ValueError('local_only must be an exact boolean') otherwise.
Solutions
- Change the value to a bare JSON true or false (no quotes, no 1/0)
- Remove the local_only key entirely if network execution is desired (defaults to false)
- Regenerate the config with a JSON serializer (json.dumps) instead of string templating
- Validate the config by running json.loads locally and asserting isinstance(v, bool) before invoking the CLI
Example fix
// before
{"local_only": "true", "integration": {...}}
// after
{"local_only": true, "integration": {...}} Defensive patterns
Strategy: type-guard
Validate before calling
v = config.get('local_only', False)
if type(v) is not bool:
raise SystemExit('local_only must be JSON true/false, not a string or number') Type guard
def is_exact_bool(v):
return type(v) is bool Try / catch
try:
run_cli(args)
except ValueError as e:
if 'local_only must be an exact boolean' in str(e):
cfg['local_only'] = cfg['local_only'] in (True, 'true', 1)
# rewrite config and retry once Prevention
- Never quote booleans in JSON configs
- Generate configs with json.dumps so types stay native
- Add a pre-commit check asserting type(v) is bool for known boolean fields
When it happens
Trigger: A config file contains "local_only": "true", "local_only": 1, or "local_only": null — any non-bool value triggers the check.
Common situations: Hand-writing the config and quoting the boolean; generating config from a template or language where booleans serialize as 0/1; YAML-ish habits leaking into JSON.
Related errors
- config must be a JSON object
- 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/ca9b6fc677653fcb.
Report an issue: GitHub.
Appendix: source
Thrown at skills/taste-application/scripts/workflow_graphs.py:138
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:
parser.exit(2, f'Offline compilation failed: {error}\n')
if __name__ == '__main__':
main()View on GitHub (pinned to 8321021c54)