{"record":{"id":"8e924aa008a996ee","repo":"sipeed/picoclaw","slug":"credential-keygen-write-public-key-q-w","errorCode":null,"errorMessage":"credential: keygen: write public key %q: %w","messagePattern":"credential: keygen: write public key %q: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/credential/keygen.go","lineNumber":58,"sourceCode":"\tif err != nil {\n\t\treturn fmt.Errorf(\"credential: keygen: marshal private key: %w\", err)\n\t}\n\tprivPEM := pem.EncodeToMemory(block)\n\n\tif err = os.WriteFile(path, privPEM, 0o600); err != nil {\n\t\treturn fmt.Errorf(\"credential: keygen: write private key %q: %w\", path, err)\n\t}\n\n\t// Marshal public key as authorized_keys line.\n\tsshPub, err := ssh.NewPublicKey(pubRaw)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"credential: keygen: marshal public key: %w\", err)\n\t}\n\tpubLine := ssh.MarshalAuthorizedKey(sshPub)\n\n\tpubPath := path + \".pub\"\n\tif err := os.WriteFile(pubPath, pubLine, 0o644); err != nil {\n\t\treturn fmt.Errorf(\"credential: keygen: write public key %q: %w\", pubPath, err)\n\t}\n\n\treturn nil\n}\n","sourceCodeStart":40,"sourceCodeEnd":63,"githubUrl":"https://github.com/sipeed/picoclaw/blob/49183d7e8daed0dba89ddbb6fcb60089401d9680/pkg/credential/keygen.go#L40-L63","documentation":"The final step of GenerateSSHKey writes the authorized_keys-format public key to path+\".pub\" with mode 0644, wrapping os.WriteFile failures. The private key at `path` was already written successfully, so this error leaves a partial key pair: a private key with no matching .pub file. The message includes the exact pub path.","triggerScenarios":"Disk fills up between the private and public key writes; directory perms change mid-run; quota hit (EDQUOT); existing .pub is immutable or a directory. ENOSPC after a large private-key write is the classic case.","commonSituations":"Tiny home partitions or container overlay limits; quota systems kicking in at the second write; antivirus/immunetable file watchers locking the .pub on some platforms; interrupted keygen retried into a half-state.","solutions":["Free space or raise quota on the target filesystem (`df -h <dir>`), then re-run keygen","Clean up the partial state before retrying: remove both `path` and `path+\".pub\"` so the pair is regenerated atomically fresh","Fix permissions on the directory if the .pub specifically cannot be created","After any successful re-run, verify the pair matches: compare `ssh-keygen -y -f <path>` output to the .pub contents"],"exampleFix":"// before\nif err := credential.GenerateSSHKey(path); err != nil {\n    return err // possible orphaned private key with no .pub\n}\n\n// after: treat keygen as a transaction - clean partial state on failure\nif err := credential.GenerateSSHKey(path); err != nil {\n    os.Remove(path)\n    os.Remove(path + \".pub\")\n    return fmt.Errorf(\"keygen failed (partial files removed): %w\", err)\n}","handlingStrategy":"try-catch","validationCode":"func spaceForKeypair(dir string) error {\n    var st syscall.Statfs_t\n    if err := syscall.Statfs(dir, &st); err != nil {\n        return err\n    }\n    if st.Bavail*uint64(st.Bsize) < 1<<20 { // need ~1 MiB headroom\n        return fmt.Errorf(\"less than 1 MiB free in %s\", dir)\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":"if err := credential.GenerateSSHKey(path); err != nil {\n    if strings.Contains(err.Error(), \"write public key\") {\n        // private key was already written; remove partial pair before any retry\n        os.Remove(path)\n        os.Remove(path + \".pub\")\n        return fmt.Errorf(\"keygen incomplete, partial files cleaned: %w\", err)\n    }\n    return err\n}","preventionTips":["Treat keygen as a transaction: on any failure, delete both path and path+\".pub\" before retrying","Ensure ~1 MiB free space and directory writability before generating keys","After keygen, verify the pair matches (ssh-keygen -y -f priv vs .pub) in your provisioning checks"],"tags":["filesystem","disk-full","keygen","partial-state","ssh"],"backgroundTag":null,"analyzedSha":"49183d7e8daed0dba89ddbb6fcb60089401d9680","analyzedAt":"2026-08-15T21:55:41.315Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}