Check a JSON array for missing, empty, or duplicate string IDs
Python
Read a saved JSON array of objects and report one-based record positions with missing, empty, or duplicate string IDs in a CLI-selected field, without changing the input.
Use this offline checker to catch ID problems in a saved JSON array before processing it elsewhere. It reports positions and counts but never removes or rewrites records. The Python 3.12 JSON documentation establishes JSON decoding, while the `collections` documentation establishes `Counter` for counting hashable values; the recipe uses those documented standard-library features.
Before you start
Python 3.12 is the intended runner; the supplied official documentation is for Python 3.12. The sources do not establish a minimum compatible version.
A readable local UTF-8 JSON file whose top-level value is an array; each record must be an object for the check to complete.
A CLI-selected `--field` name. String IDs containing only whitespace are classified as empty; non-string values are reported separately.
Only Python standard-library modules are used. No service, credential, network access, or installation is involved.
Build and check
Save the code as `check_ids.py` and prepare a small local JSON fixture.
Run it with a file path and required `--field` argument.
For each object, distinguish an absent field, a non-string value, a whitespace-only string, and a nonempty string ID.
Collect positions for each nonempty string and report IDs occurring at multiple one-based positions.
Print overall and category counts without editing, deleting, or rewriting records.
Use the error messages and checks below to diagnose invalid input or filesystem issues.
Limits to understand
The file is read wholly into memory; do not use it for untrusted, extremely large JSON input without adding suitable size limits.
Duplicate comparison is exact and case-sensitive; values are not normalized or coerced.
The code rejects a non-array top level and stops at the first non-object record rather than producing partial results.
Read errors and malformed JSON exit with status 2; they are reported on stderr. There are no retries or network timeouts because the task has no network calls.
What this example adds
This is a standalone offline CLI checker rather than a service client. It accepts a saved file and a field name, validates the expected array/object structure, and reports one-based positions while leaving input records untouched. The JSON source establishes decoding; `Counter` is documented for counting hashable values, though this version preserves IDs’ first-seen order with position lists so duplicate locations print in input order.
Run it
Save as `check_ids.py`, then run: `python check_ids.py records.json --field id`. The recipe targets Python 3.12 and uses only its standard library; it does not require network access, credentials, or an external service. The code is a proposed example and should be independently checked before publication.
records: 5
missing id: 1 at [3]
empty id: 1 at [2]
non-string id: 1 at [5]
duplicate IDs: 1
'a1': records [1, 4]
INSPECT THE SCRIPT
Inspect, copy and run the documented checks.
This browser preview builds code locally. It does not contact an API or run the code.
Default example ready.
Python example
# SPDX-License-Identifier: MIT
# Copyright (c) 2026 OpenViST contributors
import argparse
import json
import sys
from collections import Counter
from pathlib import Path
def main():
parser = argparse.ArgumentParser(
description="Report missing, empty, and duplicate string IDs in a JSON array."
)
parser.add_argument("file", help="path to a saved JSON file")
parser.add_argument("--field", required=True, help="object field containing the ID")
args = parser.parse_args()
try:
text = Path(args.file).read_text(encoding="utf-8")
except OSError as exc:
print(f"error: cannot read input file: {exc}", file=sys.stderr)
return 2
try:
records = json.loads(text)
except json.JSONDecodeError as exc:
print(f"error: invalid JSON at line {exc.lineno}, column {exc.colno}", file=sys.stderr)
return 2
if not isinstance(records, list):
print("error: top-level JSON value must be an array", file=sys.stderr)
return 2
missing = []
empty = []
non_string = []
positions_by_id = {}
for position, record in enumerate(records, start=1):
if not isinstance(record, dict):
print(f"error: record {position} is not an object", file=sys.stderr)
return 2
if args.field not in record:
missing.append(position)
continue
value = record[args.field]
if not isinstance(value, str):
non_string.append(position)
continue
if not value.strip():
empty.append(position)
continue
positions_by_id.setdefault(value, []).append(position)
duplicates = [
(value, positions)
for value, positions in positions_by_id.items()
if len(positions) > 1
]
print(f"records: {len(records)}")
print(f"missing {args.field}: {len(missing)} at {missing}")
print(f"empty {args.field}: {len(empty)} at {empty}")
print(f"non-string {args.field}: {len(non_string)} at {non_string}")
print(f"duplicate IDs: {len(duplicates)}")
for value, positions in duplicates:
print(f" {value!r}: records {positions}")
return 0
if __name__ == "__main__":
sys.exit(main())
What to verify after running
Run the synthetic fixture above and confirm the one-based positions and counts match the expected output.
Run with an empty JSON array (`[]`) and confirm all issue counts are zero and the record count is zero.
Try a malformed JSON file and confirm it reports a JSON line and column on stderr rather than a traceback.
Try a JSON object as the top-level value and a top-level array containing a non-object; confirm each is rejected with a clear error.
Try a path that does not exist and confirm a read error is reported on stderr.
Try IDs that are `null`, numeric, empty, and whitespace-only; confirm non-strings and empty strings are counted separately.
Request or format preview
Illustrative preview. No provider response, price or balance is fetched.
Code license: MIT. Keep the license notice with your copy.
Example version 0.1.0 · Documentation reviewed 2026-10-11.
Executed 6 synthetic local fixture cases in isolated CPython 3.12.15 on GitHub Actions, without network access. Declared exit codes, output assertions and input integrity checks passed. Live services, installed third-party packages and production behavior remain outside scope. Editorial approval is still required.
Related browser tools
Inspect related data locally in your browser. These tools have their own input rules and limits; they do not execute this recipe.