abi/screenshot-to-code · error · HTTPException
Failed to read report: {e}
Error message
Failed to read report: {e} What it means
HTTPException(500, "Failed to read report: ...") raised when open(filepath) or json.load(f) raises OSError or json.JSONDecodeError after the isfile() check already passed. It means the file exists but is unreadable (permissions changed, deleted mid-read) or its contents are not valid JSON — commonly a truncated/partially-written report being read while the writer is still writing it.
Source
Thrown at backend/routes/prompt_reports.py:164
total_size_bytes=total_size_bytes,
reports_directory=reports_directory,
)
@router.get("/prompt-reports/content")
async def get_prompt_report_content(filename: str) -> Any:
if PROMPT_REPORT_FILENAME_PATTERN.match(filename) is None:
raise HTTPException(status_code=400, detail="Invalid report filename")
filepath = os.path.join(get_prompt_reports_directory(), filename)
if not os.path.isfile(filepath):
raise HTTPException(status_code=404, detail="Report not found")
try:
with open(filepath, "r", encoding="utf-8") as f:
return json.load(f)
except (OSError, json.JSONDecodeError) as e:
raise HTTPException(status_code=500, detail=f"Failed to read report: {e}")
@router.post("/prompt-reports/prune", response_model=PrunePromptReportsResponse)
async def prune_prompt_reports(
request: PrunePromptReportsRequest,
) -> PrunePromptReportsResponse:
if request.max_age_days < 1:
raise HTTPException(status_code=400, detail="max_age_days must be >= 1")
run_logs_directory = get_run_logs_directory()
if not os.path.isdir(run_logs_directory):
return PrunePromptReportsResponse(deleted_count=0, freed_bytes=0)
cutoff = datetime.now() - timedelta(days=request.max_age_days)
cutoff_timestamp = cutoff.timestamp()
deleted_count = 0
freed_bytes = 0View on GitHub (pinned to d026163f58)
Solutions
- Validate the file out-of-band: python -m json.tool <file> to confirm whether it is truncated/corrupt
- Check permissions/ownership on the file and the reports directory (chmod/chown) if the OSError path is taken
- Regenerate the report (re-run the generation that produced it) to replace the corrupt file
- Fix the writer to write atomically: write to a temp file in the same directory, then os.replace() onto the final name, so readers never see partial content
Example fix
# before (writer)
with open(target, "w", encoding="utf-8") as f:
json.dump(report, f) # reader can see truncated JSON
# after (writer)
import tempfile, os
fd, tmp = tempfile.mkstemp(dir=target.parent, suffix=".tmp")
try:
with os.fdopen(fd, "w", encoding="utf-8") as f:
json.dump(report, f)
os.replace(tmp, target)
except BaseException:
os.unlink(tmp); raise Defensive patterns
Strategy: try-catch
Validate before calling
import json, os
def safe_report_content(filepath: str) -> dict:
if not os.access(filepath, os.R_OK):
raise PermissionError(filepath)
with open(filepath, encoding="utf-8") as f:
return json.load(f) # JSONDecodeError still possible for partial writes Try / catch
try:
content = client.get(f"{base}/prompt-reports/content", params={"filename": fn}).json()
except (OSError, json.JSONDecodeError):
regenerate_report(fn) # or mark as corrupt and skip; do not retry the same file blindly Prevention
- Write reports atomically (temp file + os.replace) so readers never see partial JSON
- Monitor for zero-byte or truncated report files after writer crashes
- Keep report directory ownership consistent across writer and reader processes
When it happens
Trigger: GET /prompt-reports/content on a report file that is being written concurrently (no atomic write, so a reader sees truncated JSON); file with restrictive permissions (OSError EACCES); empty file left by a crashed writer process.
Common situations: Report writer and reader share a directory without write-atomicity; process crashed mid-write leaving a half-written JSON file; files copied between users/containers losing read permissions.
Related errors
- Design systems storage is not valid JSON
- Design systems storage must contain a list
- Invalid {side} JSON: {error.msg} (line {error.lineno}, colum
- Invalid {side} payload: {error}
- Report not found
AI-assisted analysis of abi/screenshot-to-code@d026163f58 (2026-08-14).
Data as JSON: /api/errors/dae081575cb41fa1.
Report an issue: GitHub.