Skip to content

Commit ed8bdbf

Browse files
authored
Merge pull request #1097 from link-assistant/issue-1096-eebeff3a2cd7
Fix log upload argument parsing bug (#1096)
2 parents 00fccf3 + 1f5d101 commit ed8bdbf

5 files changed

Lines changed: 8165 additions & 14 deletions

File tree

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
---
2+
'@link-assistant/hive-mind': patch
3+
---
4+
5+
Fix gh-upload-log argument parsing bug causing "File does not exist" error
6+
7+
- Fixed bug where `gh-upload-log` received all arguments as a single concatenated string
8+
- The issue was caused by using `${commandArgs.join(' ')}` in command-stream template literal, which treats the entire joined string as one argument
9+
- Now using separate `${}` interpolations for each argument to ensure proper argument parsing
10+
- Also fixed: description flag is now properly passed to gh-upload-log (was only displayed, never sent)
11+
- Added comprehensive regression tests and case study documentation
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
# Case Study: Issue #1096 - Logs Upload Failed
2+
3+
## Problem Statement
4+
5+
When the hive-mind system attempted to upload a solution draft log to GitHub via `gh-upload-log`, it failed with:
6+
7+
```
8+
Error: File does not exist: "/tmp/solution-draft-log-pr-1768003849690.txt" --public --verbose
9+
```
10+
11+
The error message shows that the CLI flags (`--public --verbose`) were incorrectly included as part of the filename argument, causing `gh-upload-log` to look for a non-existent file with that combined string as its name.
12+
13+
## Timeline of Events
14+
15+
| Timestamp | Event |
16+
| ------------------- | ------------------------------------------------------------ |
17+
| 2026-01-09 23:52:55 | solve.mjs started processing issue #1083 |
18+
| 2026-01-09 23:53:34 | PR #1090 created as draft |
19+
| 2026-01-10 00:10:48 | Solution completed, attempting to upload log |
20+
| 2026-01-10 00:10:49 | Log too long (1,174,742 chars), GitHub limit is 65,536 chars |
21+
| 2026-01-10 00:10:49 | Sanitization completed (5 secrets masked) |
22+
| 2026-01-10 00:10:51 | **gh-upload-log FAILED** with argument parsing error |
23+
| 2026-01-10 00:10:51 | Fallback to truncated comment initiated |
24+
| 2026-01-10 00:10:54 | Truncated log uploaded successfully (1156KB) |
25+
| 2026-01-10 00:10:54 | Process reported as successful (but log was truncated) |
26+
27+
## Root Cause Analysis
28+
29+
### Primary Root Cause: command-stream Template Literal Argument Handling
30+
31+
The bug is in `src/log-upload.lib.mjs` at line 52:
32+
33+
```javascript
34+
// BUGGY CODE:
35+
const commandArgs = [`"${logFile}"`, publicFlag];
36+
if (verbose) {
37+
commandArgs.push('--verbose');
38+
}
39+
const uploadResult = await $`gh-upload-log ${commandArgs.join(' ')}`;
40+
```
41+
42+
**The Problem:** When using `command-stream`'s `$` template tag, a single template interpolation (`${commandArgs.join(' ')}`) is treated as a **single argument**, regardless of internal spaces. This means:
43+
44+
1. `commandArgs.join(' ')` produces: `"/tmp/file.txt" --public --verbose`
45+
2. The entire string becomes the **first positional argument** to `gh-upload-log`
46+
3. `gh-upload-log` interprets this as the file path, leading to the error
47+
48+
### Evidence from Logs
49+
50+
The displayed command showed (line 7869):
51+
52+
```
53+
Running: gh-upload-log "/tmp/solution-draft-log-pr-1768003849690.txt" --public --description "..." --verbose
54+
```
55+
56+
But the actual error showed (line 7872):
57+
58+
```
59+
Error: File does not exist: "/tmp/solution-draft-log-pr-1768003849690.txt" --public --verbose
60+
```
61+
62+
Note: The `--description` flag was missing from the error because it was never included in `commandArgs` (only in the display command).
63+
64+
### Secondary Issue: Description Flag Not Passed
65+
66+
The code builds a display command including `--description` (line 41):
67+
68+
```javascript
69+
const command = `gh-upload-log "${logFile}" ${publicFlag} ${descFlag} ${verboseFlag}`;
70+
```
71+
72+
But the actually executed command (line 52) uses `commandArgs` which doesn't include `descFlag`:
73+
74+
```javascript
75+
const commandArgs = [`"${logFile}"`, publicFlag];
76+
```
77+
78+
This means the description is never actually sent to `gh-upload-log`.
79+
80+
## Solution
81+
82+
### Fix 1: Use Separate Template Interpolations
83+
84+
Replace the single joined interpolation with individual interpolations:
85+
86+
```javascript
87+
// FIXED CODE:
88+
const publicFlag = isPublic ? '--public' : '--private';
89+
const verboseFlag = verbose ? '--verbose' : '';
90+
91+
const uploadResult = await $`gh-upload-log ${logFile} ${publicFlag} ${verboseFlag}`;
92+
```
93+
94+
Each `${}` interpolation is properly handled as a separate argument by command-stream.
95+
96+
### Fix 2: Include Description Flag
97+
98+
```javascript
99+
const descFlag = description ? ['--description', description] : [];
100+
// Then use spread operator or multiple interpolations
101+
```
102+
103+
## Testing
104+
105+
### Reproduction Test
106+
107+
```javascript
108+
// This reproduces the bug:
109+
const commandArgs = [`"${logFile}"`, '--public', '--verbose'];
110+
const uploadResult = await $`gh-upload-log ${commandArgs.join(' ')}`;
111+
// Result: gh-upload-log receives entire string as file path
112+
```
113+
114+
### Verification Test
115+
116+
```javascript
117+
// This works correctly:
118+
const uploadResult = await $`gh-upload-log ${logFile} --public --verbose`;
119+
// Result: arguments are properly parsed
120+
```
121+
122+
## Files in This Case Study
123+
124+
- `README.md` - This document
125+
- `full-log.txt` - Complete log from the failed execution (7891 lines)
126+
127+
## Related Links
128+
129+
- Original Issue: https://github.com/link-assistant/hive-mind/issues/1096
130+
- Pull Request: https://github.com/link-assistant/hive-mind/pull/1097
131+
- gh-upload-log Tool: https://github.com/link-foundation/gh-upload-log
132+
- Previous Case Study: Issue #587 (large file upload limitations)
133+
134+
## Lessons Learned
135+
136+
1. **Template literals in shell commands require careful handling**: Each `${}` interpolation in command-stream is treated as a single argument. Don't join multiple arguments into one string.
137+
138+
2. **Display vs execution divergence is dangerous**: The code displayed one command but executed a different one, making debugging harder.
139+
140+
3. **Log truncation should be considered a failure**: The "successful" completion masked the actual upload failure. Truncated logs lose critical debugging information.
141+
142+
4. **Tests should verify actual command execution**: The existing tests verified argument building logic but didn't test actual command execution with command-stream.

0 commit comments

Comments
 (0)