gastownhall/beads · error

failed to update

Error message

failed to update %s: %w

What it means

After ReplaceSectionWithOpts reports changes, updateAgentFile writes the updated file back with os.WriteFile (mode 0644). A write failure is wrapped here, meaning the beads section was computed as changed but the updated markdown could not be persisted to disk.

Solutions

  1. Check and fix write permissions on the file (chmod/chown)
  2. Ensure the working tree is writable before running bd init
  3. Free disk space / raise quota if the disk is full
  4. Check chattr +i or sandbox policies blocking writes and remove the restriction

Example fix

// before: read-only checkout
$ bd init
failed to update AGENTS.md: read-only file system
// after
$ chmod -R u+w . && bd init
Defensive patterns

Strategy: validation

Validate before calling

[ -w AGENTS.md ] || { echo "AGENTS.md not writable" >&2; exit 1; }

Try / catch

if err := addAgentsInstructions(...); err != nil && strings.Contains(err.Error(), "failed to update ") { log.Fatalf("cannot persist updated agent file: %v", err) }

Prevention

When it happens

Trigger: Updating an existing agent markdown whose beads section changed, but the file/directory is unwritable at write time (permissions changed between read and write, read-only mount, disk full).

Common situations: CI workspaces made read-only after checkout; another process holding the file or flipping permissions; disk quota exceeded; immutable bit set on the file.

Understand the failure class

Background: "Permission denied" / "Failed to write" file errors: why a library can't write its files to disk (EACCES, EPERM, ENOSPC) and how to fix them — this error's family across 43 libraries.

Related errors


AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30). Data as JSON: /api/errors/3482a047892117fc. Report an issue: GitHub.

Appendix: source

Thrown at cmd/bd/init_agent.go:99

		// Preserve existing full profile when minimal is requested (avoid information loss)
		effectiveProfile := profile
		existingMeta := agents.ParseMarker(contentStr[strings.Index(contentStr, "<!-- BEGIN BEADS INTEGRATION"):])
		if existingMeta != nil && existingMeta.Profile == agents.ProfileFull && profile == agents.ProfileMinimal {
			effectiveProfile = agents.ProfileFull
			if verbose {
				fmt.Printf("  ℹ %s already has full profile; preserving (higher-information) content\n", filename)
			}
		}

		// Update existing section to latest versioned format (upgrades legacy markers)
		updated, changed, replaceErr := agents.ReplaceSectionWithOpts(contentStr, effectiveProfile, opts)
		if replaceErr != nil {
			return fmt.Errorf("failed to update beads section in %s: %w", filename, replaceErr)
		}
		if changed {
			// #nosec G306 - markdown needs to be readable
			if err := os.WriteFile(filename, []byte(updated), 0644); err != nil {
				return fmt.Errorf("failed to update %s: %w", filename, err)
			}
			if verbose {
				fmt.Printf("  %s Updated beads section in %s to latest format\n", ui.RenderPass("✓"), filename)
			}
		} else if verbose {
			fmt.Printf("  %s already has current agent instructions\n", filename)
		}
		return nil
	}

	// Append beads section with profile metadata
	newContent := contentStr
	if !strings.HasSuffix(newContent, "\n") {
		newContent += "\n"
	}

	newContent += "\n" + agents.RenderSectionWithOpts(profile, opts)

View on GitHub (pinned to 71377f2769)