Skip to content

Commit a269eb3

Browse files
committed
fix: handle Reddit wiki size limits properly
- Add automatic content trimming when approaching Reddit's 524KB wiki limit - Implement smart date-based trimming to stay under 90% of limit - Add detailed error messages for 403 errors without debug mode - Include wiki size information in all error and success messages - Show clear context when wiki updates fail due to size constraints This fixes the OpenSignups wiki update failures by automatically removing older days when the content would exceed Reddit's size limits.
1 parent e5dc0ba commit a269eb3

File tree

1 file changed

+146
-22
lines changed

1 file changed

+146
-22
lines changed

modlog_wiki_publisher.py

Lines changed: 146 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1051,24 +1051,63 @@ def build_wiki_content(actions: List, config: Dict[str, Any]) -> str:
10511051
actions_by_date[date_str].append(action)
10521052

10531053
# Build content - include ID column for tracking actions across the table
1054+
# Reddit wiki page size limit (512 KB)
1055+
REDDIT_WIKI_LIMIT = 524288
1056+
WARNING_THRESHOLD = int(REDDIT_WIKI_LIMIT * 0.90) # Start trimming at 90%
1057+
1058+
sorted_dates = sorted(actions_by_date.keys(), reverse=True)
10541059
content_parts = [timestamp_header]
1055-
for date_str in sorted(actions_by_date.keys(), reverse=True):
1056-
content_parts.append(f"## {date_str}")
1057-
content_parts.append("| Time | Action | ID | Moderator | Content | Reason | Inquire |")
1058-
content_parts.append("|------|--------|----|-----------|---------|--------|---------|")
1059-
1060+
footer_parts = ["---", "", "*This modlog is automatically maintained by [RedditModLog](https://github.com/bakerboy448/RedditModLog) bot.*"]
1061+
1062+
# Build the full content first
1063+
full_content_parts = []
1064+
for date_str in sorted_dates:
1065+
date_parts = [f"## {date_str}"]
1066+
date_parts.append("| Time | Action | ID | Moderator | Content | Reason | Inquire |")
1067+
date_parts.append("|------|--------|----|-----------|---------|--------|---------|")
1068+
10601069
for action in sorted(actions_by_date[date_str], key=lambda x: x.created_utc, reverse=True):
10611070
entry = format_modlog_entry(action, config)
1062-
content_parts.append(f"| {entry['time']} | {entry['action']} | {entry['id']} | {entry['moderator']} | {entry['content']} | {entry['reason']} | {entry['inquire']} |")
1063-
1064-
content_parts.append("") # Empty line between dates
1065-
1066-
# Add bot attribution footer after all content
1067-
content_parts.append("---")
1068-
content_parts.append("")
1069-
content_parts.append("*This modlog is automatically maintained by [RedditModLog](https://github.com/bakerboy448/RedditModLog) bot.*")
1070-
1071-
return "\n".join(content_parts)
1071+
date_parts.append(f"| {entry['time']} | {entry['action']} | {entry['id']} | {entry['moderator']} | {entry['content']} | {entry['reason']} | {entry['inquire']} |")
1072+
1073+
date_parts.append("") # Empty line between dates
1074+
full_content_parts.append("\n".join(date_parts))
1075+
1076+
# Check size and trim if necessary
1077+
included_dates = []
1078+
current_size = len((timestamp_header + "\n".join(footer_parts)).encode('utf-8'))
1079+
skipped_days = 0
1080+
1081+
for i, date_content in enumerate(full_content_parts):
1082+
test_size = current_size + len(date_content.encode('utf-8'))
1083+
1084+
# If adding this date would exceed the warning threshold, stop adding dates
1085+
if test_size > WARNING_THRESHOLD:
1086+
skipped_days = len(sorted_dates) - i
1087+
if skipped_days > 0:
1088+
logger.warning(f"Wiki approaching size limit - trimming {skipped_days} oldest day(s) of entries")
1089+
logger.warning(f"Excluded dates: {sorted_dates[i:]}")
1090+
1091+
# Add a notice about trimmed content
1092+
content_parts.append(f"\n**Note:** {skipped_days} older day(s) trimmed due to wiki size limits.")
1093+
content_parts.append(f"Only showing entries from {sorted_dates[i-1] if i > 0 else 'today'} onwards.\n")
1094+
break
1095+
1096+
content_parts.append(date_content)
1097+
included_dates.append(sorted_dates[i])
1098+
current_size = test_size
1099+
1100+
# Add footer
1101+
content_parts.extend(footer_parts)
1102+
1103+
final_content = "\n".join(content_parts)
1104+
final_size = len(final_content.encode('utf-8'))
1105+
1106+
if skipped_days > 0:
1107+
logger.info(f"Wiki content size after trimming: {final_size:,} bytes ({(final_size/REDDIT_WIKI_LIMIT)*100:.1f}% of limit)")
1108+
logger.info(f"Included {len(included_dates)} days, excluded {skipped_days} days")
1109+
1110+
return final_content
10721111

10731112
def setup_reddit_client(config: Dict[str, Any]):
10741113
"""Initialize Reddit API client"""
@@ -1092,9 +1131,26 @@ def setup_reddit_client(config: Dict[str, Any]):
10921131
def update_wiki_page(reddit, subreddit_name: str, wiki_page: str, content: str, force: bool = False):
10931132
"""Update wiki page with content, using hash caching to avoid unnecessary updates"""
10941133
try:
1134+
# Reddit wiki page size limit (512 KB)
1135+
REDDIT_WIKI_LIMIT = 524288
1136+
1137+
# Check content size
1138+
content_size = len(content.encode('utf-8'))
1139+
if content_size > REDDIT_WIKI_LIMIT:
1140+
logger.error(f"Wiki content size ({content_size:,} bytes) exceeds Reddit's limit ({REDDIT_WIKI_LIMIT:,} bytes)")
1141+
logger.error(f"Content is {content_size - REDDIT_WIKI_LIMIT:,} bytes over the limit")
1142+
raise ValueError(f"Wiki content too large: {content_size:,} bytes (limit: {REDDIT_WIKI_LIMIT:,} bytes)")
1143+
1144+
# Check if we're getting close to the limit (warn at 95%)
1145+
warning_threshold = int(REDDIT_WIKI_LIMIT * 0.95)
1146+
if content_size > warning_threshold:
1147+
percent_used = (content_size / REDDIT_WIKI_LIMIT) * 100
1148+
logger.warning(f"Wiki content size ({content_size:,} bytes) is {percent_used:.1f}% of Reddit's limit")
1149+
logger.warning(f"Only {REDDIT_WIKI_LIMIT - content_size:,} bytes remaining before hitting limit")
1150+
10951151
# Calculate content hash
10961152
content_hash = get_content_hash(content)
1097-
1153+
10981154
# Check if content has changed (unless forced)
10991155
cached_hash = get_cached_wiki_hash(subreddit_name, wiki_page)
11001156
if cached_hash == content_hash:
@@ -1103,23 +1159,91 @@ def update_wiki_page(reddit, subreddit_name: str, wiki_page: str, content: str,
11031159
else:
11041160
logger.info(f"Wiki content unchanged for /r/{subreddit_name}/wiki/{wiki_page}, skipping update")
11051161
return False
1106-
1107-
# Update the wiki page
1162+
1163+
# Check existing wiki page size if it exists
11081164
subreddit = reddit.subreddit(subreddit_name)
1165+
try:
1166+
existing_wiki = subreddit.wiki[wiki_page]
1167+
existing_size = len(existing_wiki.content_md.encode('utf-8'))
1168+
logger.debug(f"Existing wiki page size: {existing_size:,} bytes")
1169+
1170+
# If new content would make page exceed limit, we need to handle it
1171+
if existing_size > warning_threshold:
1172+
logger.warning(f"Existing wiki page already at {existing_size:,} bytes ({(existing_size/REDDIT_WIKI_LIMIT)*100:.1f}% of limit)")
1173+
1174+
# If we're trying to add more content to an already large page
1175+
if content_size >= existing_size:
1176+
logger.error(f"Cannot increase wiki size from {existing_size:,} to {content_size:,} bytes - too close to limit")
1177+
logger.error("Consider reducing retention_days or max_wiki_entries_per_page in config")
1178+
raise ValueError(f"Wiki page too large to update safely")
1179+
except Exception as e:
1180+
# Wiki page might not exist yet, that's okay
1181+
if "404" not in str(e) and "not found" not in str(e).lower():
1182+
logger.debug(f"Could not check existing wiki size: {e}")
1183+
1184+
# Update the wiki page
1185+
logger.info(f"Attempting to update wiki page with {content_size:,} bytes of content")
11091186
subreddit.wiki[wiki_page].edit(
11101187
content=content,
11111188
reason="Automated modlog update"
11121189
)
1113-
1190+
11141191
# Update the cached hash
11151192
update_cached_wiki_hash(subreddit_name, wiki_page, content_hash)
1116-
1193+
11171194
action_type = "force updated" if force else "updated"
11181195
logger.info(f"Successfully {action_type} wiki page: /r/{subreddit_name}/wiki/{wiki_page}")
1196+
logger.info(f"Final wiki size: {content_size:,} bytes ({(content_size/REDDIT_WIKI_LIMIT)*100:.1f}% of Reddit's limit)")
11191197
return True
1120-
1198+
1199+
except praw.exceptions.RedditAPIException as e:
1200+
# Handle specific Reddit API errors
1201+
error_messages = []
1202+
for item in e.items:
1203+
error_messages.append(f"{item.error_type}: {item.message}")
1204+
1205+
logger.error(f"Reddit API error updating wiki page: {', '.join(error_messages)}")
1206+
1207+
# Check if it's a size-related error
1208+
if any('too long' in msg.lower() or 'size' in msg.lower() for msg in error_messages):
1209+
logger.error(f"Wiki content size ({content_size:,} bytes) likely exceeds Reddit's limit")
1210+
logger.error("Try reducing retention_days or max_wiki_entries_per_page in config")
1211+
1212+
raise
1213+
11211214
except Exception as e:
1122-
logger.error(f"Failed to update wiki page: {e}")
1215+
error_str = str(e)
1216+
1217+
# Provide more context for common errors
1218+
if "403" in error_str:
1219+
logger.error(f"403 Forbidden error updating wiki page /r/{subreddit_name}/wiki/{wiki_page}")
1220+
logger.error("Possible causes:")
1221+
logger.error(" 1. Wiki page size limit exceeded (current content: {content_size:,} bytes)")
1222+
logger.error(" 2. Bot lacks wiki edit permissions on this subreddit")
1223+
logger.error(" 3. Wiki page is locked or restricted")
1224+
logger.error(" 4. Rate limiting (too many requests)")
1225+
1226+
# Check if we're near the size limit
1227+
if content_size > REDDIT_WIKI_LIMIT * 0.95:
1228+
logger.error(f"LIKELY CAUSE: Content size ({content_size:,} bytes) is very close to Reddit's limit ({REDDIT_WIKI_LIMIT:,} bytes)")
1229+
1230+
# Try to check existing page size for context
1231+
try:
1232+
existing_wiki = subreddit.wiki[wiki_page]
1233+
existing_size = len(existing_wiki.content_md.encode('utf-8'))
1234+
logger.error(f"Current wiki page size: {existing_size:,} bytes")
1235+
if existing_size > REDDIT_WIKI_LIMIT * 0.95:
1236+
logger.error("Wiki page is already near Reddit's size limit!")
1237+
except:
1238+
pass
1239+
1240+
elif "404" in error_str:
1241+
logger.error(f"Wiki page /r/{subreddit_name}/wiki/{wiki_page} not found")
1242+
logger.error("The wiki page might not exist yet or the name is incorrect")
1243+
1244+
else:
1245+
logger.error(f"Failed to update wiki page: {e}")
1246+
11231247
raise
11241248

11251249
def process_modlog_actions(reddit, config: Dict[str, Any]) -> List:

0 commit comments

Comments
 (0)