{"record":{"id":"99fbf9140fc4e7d6","repo":"HKUDS/Vibe-Trading","slug":"timestamp-must-not-be-empty","errorCode":null,"errorMessage":"timestamp must not be empty","messagePattern":"timestamp must not be empty","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"agent/src/governance/manifest.py","lineNumber":394,"sourceCode":"        tool_names: Tool registry names, e.g. ``ToolRegistry.tool_names``.\n        package_versions: ``{package: version_or_None}``; see\n            :func:`collect_key_package_versions` for a ready-made curated\n            collector.\n        extra: Small caller-defined composition dimensions (e.g.\n            ``{\"provider\": \"openrouter\", \"model\": \"deepseek/deepseek-v3.2\"}``).\n\n    Returns:\n        A new :class:`RunManifest` with ``manifest_hash`` computed over the\n        composition (excluding ``run_id``/``timestamp``).\n\n    Raises:\n        ValueError: ``run_id``/``timestamp`` is empty, or ``skills`` contains\n            two records with the same name.\n    \"\"\"\n    if not run_id or not run_id.strip():\n        raise ValueError(\"run_id must not be empty\")\n    if not timestamp or not timestamp.strip():\n        raise ValueError(\"timestamp must not be empty\")\n\n    if isinstance(skills, Mapping):\n        skill_records = tuple(\n            sorted(\n                (SkillRecord.from_content(name, content) for name, content in skills.items()),\n                key=lambda record: record.name,\n            )\n        )\n    else:\n        skill_records = tuple(sorted(skills, key=lambda record: record.name))\n        names = [record.name for record in skill_records]\n        if len(names) != len(set(names)):\n            raise ValueError(f\"duplicate skill names in manifest input: {names}\")\n\n    tools_snapshot = ToolRegistrySnapshot.from_names(tool_names)\n    pv_pairs = _pairs(package_versions)\n    extra_pairs = _pairs(extra)\n","sourceCodeStart":376,"sourceCodeEnd":412,"githubUrl":"https://github.com/HKUDS/Vibe-Trading/blob/80ffdda44c5c4db0dd84d70e051cca591cea67df/agent/src/governance/manifest.py#L376-L412","documentation":"build_run_manifest requires a non-empty timestamp string; empty or whitespace-only values are rejected so manifests always carry a creation time.","triggerScenarios":"Calling build_run_manifest(timestamp=\"\") or timestamp=\"   \", e.g. when the caller's clock/timestamp helper returned nothing.","commonSituations":"Timestamp sourced from an optional header or metadata dict that was absent; serialization dropping the field; tests omitting it.","solutions":["Pass an explicit ISO-8601 UTC timestamp, e.g. datetime.now(timezone.utc).isoformat()","Default the timestamp at the call site when missing","Validate required manifest inputs in one place before building"],"exampleFix":"# before\nbuild_run_manifest(run_id=rid, timestamp=meta.get(\"ts\", \"\"), ...)\n# after\nfrom datetime import datetime, timezone\nts = meta.get(\"ts\") or datetime.now(timezone.utc).isoformat()\nbuild_run_manifest(run_id=rid, timestamp=ts, ...)","handlingStrategy":"validation","validationCode":"from datetime import datetime, timezone\ntimestamp = (timestamp or \"\").strip() or datetime.now(timezone.utc).isoformat()","typeGuard":"def is_valid_timestamp(ts: str) -> bool:\n    return bool(ts and ts.strip())","tryCatchPattern":"except ValueError as e: if 'timestamp' in str(e): stamp with current UTC time and retry","preventionTips":["Default the timestamp at the call site","Use timezone-aware isoformat strings","Centralize manifest input validation"],"tags":["manifest","timestamp","missing-required-field","python"],"backgroundTag":"missing-required-field","analyzedSha":"80ffdda44c5c4db0dd84d70e051cca591cea67df","analyzedAt":"2026-08-28T12:46:38.989Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}