{"record":{"id":"29d550d684a72d97","repo":"can1357/oh-my-pi","slug":"replace-memory-files-contains-an-invalid-file-entr","errorCode":null,"errorMessage":"replace_memory_files contains an invalid file entry","messagePattern":"replace_memory_files contains an invalid file entry","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/sharpshooter/consolidate.ts","lineNumber":247,"sourceCode":"): ReplacementFile[] {\n\tconst toolCalls = content.filter(\n\t\t(block): block is { type: \"toolCall\"; name: string; arguments: unknown } =>\n\t\t\ttypeof block === \"object\" && block !== null && \"type\" in block && block.type === \"toolCall\",\n\t);\n\tif (toolCalls.length !== 1 || toolCalls[0]?.name !== replaceMemoryFilesTool.name) {\n\t\tthrow new Error(\"sharpshooter consolidation must call replace_memory_files exactly once\");\n\t}\n\n\tconst args = toolCalls[0].arguments;\n\tif (!args || typeof args !== \"object\" || !(\"files\" in args) || !Array.isArray(args.files)) {\n\t\tthrow new Error(\"replace_memory_files requires a files array\");\n\t}\n\n\tconst seen = new Set<SharpshooterMemoryFile>();\n\tconst files: ReplacementFile[] = [];\n\tfor (const item of args.files) {\n\t\tif (!item || typeof item !== \"object\" || !(\"name\" in item) || !(\"content\" in item)) {\n\t\t\tthrow new Error(\"replace_memory_files contains an invalid file entry\");\n\t\t}\n\t\tconst name = item.name;\n\t\tconst rawContent = item.content;\n\t\tif (!isMemoryFileName(name) || typeof rawContent !== \"string\") {\n\t\t\tthrow new Error(\"replace_memory_files contains an invalid file entry\");\n\t\t}\n\t\tif (seen.has(name)) throw new Error(`replace_memory_files contains duplicate ${name}`);\n\t\tseen.add(name);\n\t\tconst redacted = redactSecrets(rawContent);\n\t\tlet lines = redacted.length > 0 ? 1 : 0;\n\t\tfor (let index = 0; index + 1 < redacted.length; index++) {\n\t\t\tif (redacted.charCodeAt(index) === 10) lines += 1;\n\t\t}\n\t\tif (lines > SHARPSHOOTER_MAX_FILE_LINES) {\n\t\t\tthrow new Error(`${name} exceeds the ${SHARPSHOOTER_MAX_FILE_LINES}-line limit`);\n\t\t}\n\t\tfiles.push({ name, content: redacted });\n\t}","sourceCodeStart":229,"sourceCodeEnd":265,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/sharpshooter/consolidate.ts#L229-L265","documentation":"Each entry of the `files` array in a `replace_memory_files` call must be a non-null object containing both `name` and `content`, the name must be one of the known sharpshooter memory filenames, and content must be a string. This error is thrown when either the structural check (missing name/content, null/primitive entry) or the value check (unknown name or non-string content) fails.","triggerScenarios":"An entry in `args.files` is null, a primitive, or missing `name`/`content` keys; or `name` is not one of SHARPSHOOTER_MEMORY_FILES; or `content` is a number/boolean/object instead of a string.","commonSituations":"Model inventing a new memory filename not in the allowed set; hallucinated entries with truncated or typed content (e.g. numeric line counts); null entries from malformed JSON streaming.","solutions":["Use exactly the allowed memory file names for `name` (check SHARPSHOOTER_MEMORY_FILES / the tool description).","Ensure every entry has both `name` (string) and `content` (string) keys.","Regenerate the tool call with a stricter schema (enum on name, type string on content).","Retry the run — this is model output, not caller input."],"exampleFix":"// before\n{ files: [{ name: \"notes.md\", content: 42 }] }\n// after: allowed name, string content\n{ files: [{ name: \"AGENTS.md\", content: \"...\" }] }","handlingStrategy":"validation","validationCode":"const valid = files.every(f => f && typeof f === \"object\" && \"name\" in f && \"content\" in f);","typeGuard":"const isReplacementFile = (x: unknown): x is { name: unknown; content: unknown } =>\n  typeof x === \"object\" && x !== null && \"name\" in x && \"content\" in x;","tryCatchPattern":"try {\n  return parseReplacementFiles(call, currentFiles);\n} catch (err) {\n  if (err instanceof Error && err.message.includes(\"invalid file entry\")) {\n    return retryConsolidation();\n  }\n  throw err;\n}","preventionTips":["Pin `name` to an enum in the tool schema.","Require `content` to be type string in the schema.","Test consolidation against weak models that emit malformed JSON."],"tags":["validation","tool-calling","schema"],"backgroundTag":"tool-arguments-schema-violation","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}